MTV模型:(django)
- M:模型层(models.py)
- T:templates
- V:views
MVC模型:
- M:模型层(models.py)
- V:视图层(views.py)
- C:控制层(Controller) urls.py
django的MTV本质上也是MVC模型。
django自动帮我们创建
class Book(models.Model):
name = models.CharField(max_length=32)
# ManyToMany会自动帮我们创建第三张关联的表
authors = models.ManyToManyField(to='Author')
class Author(models.Model):
name = models.CharField(max_length=32)
纯手动创建第三张表,这样创建的表,django的ORM的正向反向查询会不支持
class Book(models.Model):
name = models.CharField(max_length=32)
class Author(models.Model):
name = models.CharField(max_length=32)
class Book2Author(models.Model):
book = models.ForeignKey(to='Book')
author = models.ForeignKey(to='Author')
info = models.CharField(max_length=32)
半自动创建第三张表,这种方式可扩展性高,并且能符合ORM查询的规范。
我除了插入它们之间的关系外,还能插入一些其他的字段。这种方式也是以后用的最多的。
class Book(models.Model):
name = models.CharField(max_length=32)
authors = models.ManyToManyField(to='Author', through='Book2Author', through_fields=('book','author')))
class Author(models.Model):
name = models.CharField(max_length=32)
# 也可以把外键建在这张表
# book = models.ManyToManyField(to='Book', through='Book2Author', through_fields=('author','book'))
class Book2Author(models.Model):
book = models.ForeignKey(to='Book') # django在创建时会自动在后面加_id
author = models.ForeignKey(to='Author') # django在创建时会自动在后面加_id
info = models.CharField(max_length=32)
举例:支持对象与字段查询,支持正向与反向查询
from app01 import models
# 查询书籍对应的作者
res = models.Book.objects.filter(pk=1).values('authors__name')
print(res)
book_obj = models.Book.objects.filter(pk=1).first()
print(book_obj.authors.all())
# 查询作者对应的书籍
res = models.Author.objects.filter(pk=1).values('book__name')
print(res)
# 查询书籍对应的信息
res = models.Book.objects.filter(pk=1).values('book2author__info')
print(res)
res = models.Book.objects.filter(pk=1).values('book2author__author__name')
print(res)
在开始学习ajax之前,先来看一下前后端传输数据的编码格式:contentType
urlencoded:默认的类型(enctype="application/x-www-form-urlencoded"),不支持文件传输。form表单
- 对应的数据格式:name=jason&password=666
- 后端获取数据:request.POST
- django会将urlencoded编码的数据解析后自动放到request.POST
formdata:指定编码,支持文件传输(enctype="multipart/form-data")。form表单
- form表单传输文件的编码格式
- 后端获取文件格式数据:request.FILES
- 后端获取普通键值对数据:request.POST
application/json:这个不是form表单里指定的,而是在ajax内指定使用json格式传递字符串
- ajax发送json格式的数据要用的编码
- 编码与数据格式要一致
- 浏览器窗口手动输入网址:get请求
- a标签的href属性:get请求
- form表单:get/post请求(默认是get请求)
- ajax:get/post请求
ajax的特点:
- 异步提交:即提交任务后可以继续提交其他任务,而不用在原地等待结果
- 局部刷新:即只在浏览器页面用到数据的位置刷新,不会刷新整个页面
- 提交的地址(url)
- 提交的方式(type)
- 提交的数据(data)
- 回调函数(success)
//给id为d1的按钮绑定点击事件,向后端发送数据,然后通过回调函数拿到后端处理的结果
$('#d1').click(function () {
$.ajax({
//提交的地址,可以不写,默认发到当前页面打开的地址
url:'/index/,
//提交的方式
type:'post',
//提交的数据
data:{'name':'shj', 'password':'123'},
//回调函数
success:function (data) { //data接收到的就是异步提交返回的结果
alert(data)
}
})
})
ajax默认传输数据的编码格式也是urlencoded。
前后端在传输数据时,数据与编码格式要一一对应,你传的是json格式就不要忘了指定编码。
只要是post请求,一定要去配置文件中注销这一段:
在前端页面展示三个input框,然后将前两个框的和通过ajax异步提交渲染到第三个框。
+=
def index(request):
if request.method == 'POST':
i1 = request.POST.get('i1')
i2 = request.POST.get('i2')
i3 = int(i1) + int(i2)
print(i3, type(i3))
return HttpResponse(i3)
return render(request, 'index.html')
前端:
$('#d1').on('click', function () {
$.ajax({
url:'', //可以不写,默认就是当前打开的页面
type:'post',
contentType:'application/json',
data:JSON.stringify({'name':'shj','hobby':'study'}),
success:function (data) {
//可以为空
}
})
});
后端:request.body只有传递json格式的数据时才有用,能被打印查看
def index(request):
if request.method == 'POST':
import json
data = request.body
print(data) # b'{"name":"shj","hobby":"study"}'
res = data.decode('utf-8')
print(res, type(res)) # {"name":"shj","hobby":"study"}
dic = json.loads(res)
print(dic, type(dic)) # {'name': 'shj', 'hobby': 'study'}
return HttpResponse('OK')
return render(request, 'index.html')
借助内置对象FormData可以传输文件,也可以传输普通的键值对。格式如下:
formdata.append('键', '值')
前端:
$('#d1').click(function () {
let formdata = new FormData();
// FormData对象不仅仅可以传文件还可以传普通的键值对
formdata.append('name','jason');
// 获取input框存放的文件
//$('#i1')[0].files[0]
formdata.append('myfile',$('#i1')[0].files[0]);
$.ajax({
url:'',
type:'post',
data:formdata,
// ajax发送文件需要修改两个固定的参数
processData:false, // 告诉浏览器不要处理我的数据
contentType:false, // 不要用任何的编码,就用formdata自带的编码格式,django能够自动识别该formdata对象
// 回调函数
success:function (data) {
alert(data)
}
})
});
后端:文件解析后放在request.FILES,普通的键值对解析后放在request.POST中
def index(request):
if request.method == 'POST':
file_obj = request.FILES.get('myfile')
print(file_obj.name)
with open(file_obj.name,'wb') as f:
for line in file_obj.chunks(): # 这里.chunks()可加可不加,反正for循环也是一行一读
f.write(line)
return HttpResponse('上传成功')
return render(request, 'index.html')
- form表单不支持异步提交、局部刷新
- form表单不支持传输json格式的数据
- form表单与ajax默认传输数据的编码格式都是urlencoded
先建一张表:
class Book2(models.Model):
name = models.CharField(max_length=32)
如果我要100条数据:
def book_list(request):
for i in range(100):
models.Book2.objects.create(name='第%s本书'%i)
return render(request,'booklist.html',locals())
上面插入100条数据的时候,明显感觉到速度很慢。如果插入10000条呢,现在就要用到一个批量插入。
def book_list(request):
l = []
for i in range(10000):
l.append(models.Book2(name='第%s本书' % i)) # 实例化出一些对象
models.Book2.objects.bulk_create(l)
补充一点:前端需要根据当前页面展示第几页。
后端:
from django.shortcuts import render,HttpResponse
from app01 import models
from app01.utils import my_page
def booklist(request):
book_list = models.Book2.objects.all()
all_count = book_list.count() # 所有的数据总数
current_page = request.GET.get('page',1) # 获取当前页码,默认第一页
page_obj = my_page.Pagination(current_page=current_page,all_count=all_count)
page_queryset = book_list[page_obj.start:page_obj.end] # 切片,每页展示多少条
return render(request,'booklist.html',locals())
前端:渲染的是带有bootstrap样式的分页器
在应用app01下新建一个utils文件夹,在下面新建 my_page.py文件
class Pagination(object):
def __init__(self, current_page, all_count, per_page_num=2, pager_count=11):
"""
封装分页相关数据
:param current_page: 当前页
:param all_count: 数据库中的数据总条数
:param per_page_num: 每页显示的数据条数
:param pager_count: 最多显示的页码个数
用法:
queryset = model.objects.all()
page_obj = Pagination(current_page,all_count)
page_data = queryset[page_obj.start:page_obj.end]
获取数据用page_data而不再使用原始的queryset
获取前端分页样式用page_obj.page_html
"""
try:
current_page = int(current_page)
except Exception as e:
current_page = 1
if current_page < 1:
current_page = 1
self.current_page = current_page
self.all_count = all_count
self.per_page_num = per_page_num
# 总页码
all_pager, tmp = divmod(all_count, per_page_num)
if tmp:
all_pager += 1
self.all_pager = all_pager
self.pager_count = pager_count
self.pager_count_half = int((pager_count - 1) / 2)
@property
def start(self):
return (self.current_page - 1) * self.per_page_num
@property
def end(self):
return self.current_page * self.per_page_num
def page_html(self):
# 如果总页码 < 11个:
if self.all_pager <= self.pager_count:
pager_start = 1
pager_end = self.all_pager + 1
# 总页码 > 11
else:
# 当前页如果<=页面上最多显示11/2个页码
if self.current_page <= self.pager_count_half:
pager_start = 1
pager_end = self.pager_count + 1
# 当前页大于5
else:
# 页码翻到最后
if (self.current_page + self.pager_count_half) > self.all_pager:
pager_end = self.all_pager + 1
pager_start = self.all_pager - self.pager_count + 1
else:
pager_start = self.current_page - self.pager_count_half
pager_end = self.current_page + self.pager_count_half + 1
page_html_list = []
# 添加前面的nav和ul标签
page_html_list.append('''
''')
return ''.join(page_html_list)