Django之Ajax传输数据
MTV与MVC模型
MTV与MVC都是模型,只不过MTV是django自己定义的,具体看一下他们的意思
MTV模型(django)
M:模型层(models.py)
T:templates文件夹
V:视图层(views)
MVC模型
M:模型层
V:视图层(views.py)
C:控制器(Controller) urls.py
总结:本质上django的MTV也是MVC
前后端传输数据编码格式
首先,在我们不指定传输数据的时候,默认的contentType都是urlencoded
urlencoded
对应的数据格式:name=jason&password=555
后端获取数据:request.POST
PS:django会将urlencded编码的数据解析自动放到request.POST
formdata
form表单传输文件的编码格式
后端获取文件格式数据:request.FILES
后端获取普通键值对数据:request.POST
application/json
form表单不支持,Ajax支持
Ajax发送json格式数据
需要注意的点
编码与数据格式要一致
Ajax(重点掌握)
Ajax支持异步提交数据,局部刷新页面,这种情况我们在好多页面都会看到,那我们要如何做到呢?先来学习Ajax的基础语法~~~记住四兄弟即可
提交的地址(url):控制数据的提交地址,不写默认往当前位置提交
提交的方式(type):默认是get,要将get请求换成post
提交的数据(data):类似于字典的格式,字典具有一一标识的优点
回调函数(success):function(data){}data接收到的后端传输的数据
基本结构如下:
<script> //记得写在html页面的最下方或者是你写在js里面,然后引入 $('绑定事件的id').click(function () { //给你要让Ajax触发的按钮绑定一个事件 $.ajax({ //Ajax的固定写法,在{}里面写你的四兄弟 url:'在这里写你的提交的路径', //不写默认是当前页面提交 type:'post' , //将请求方式从默认的get改成post data:{}, //这个固定是data,后面放的是字典的形式 success:function (data) { //回调函数,拿到的是提交过后的数据,就是后端处理过后的数据,不要忘记参数,这个参数就是接收后端处理过后的数据 //对接受到的数据进行处理,做的是局部刷新操作
alert(123)
} }) }) </script>
自己尝试着写一个不跳转的动态页面,比如1+1=2
Ajax实现简单版页面局部刷新
我们首先需要的就是自己定义三个input框,然后动态获取到前两个框中的值,通过Ajax放到第三个input框中,代码演示如下
<input type="text" id="i1" >+<input type="text" id="i2" >=<input type="text" id="i3"> <button id="b1">点我点我</button> <script> $('#b1').click(function () { $.ajax({ url:'/index/', type:'post', data:{'i1':$('#i1').val(),'i2':$('#i2').val()}, success:function (data) { $('#i3').val(data) } }) }) </script>
后端数据处理
def index(request): if request.method=='POST': i1=request.POST.get('i1') i2=request.POST.get('i2') print(i1,i2) res=int(i1)+int(i2) print(res,type(res)) return HttpResponse(res) return render(request,'index.html')
注意:Ajax不要与form表单联合使用,直接使用input框就可以
Ajax实现json格式数据的传输
具体代码展示如下
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </head> <body> <p>username:<input type="text" id="u1"></p> <p>password:<input type="password" id="p1"></p> <button id="b1">提交</button> <input type="text" id="i1"> <script> $('#b1').click(function () { $.ajax({ url:'', type:'post', contentType:'application/json', data:JSON.stringify({ 'username':$('#u1').val(), 'password':$('#p1').val() }), success:function (data) { $('#i1').val(data) } }) }) </script> </body> </html>
def jsonajax(request): print('method:', request.method) print('POST:', request.POST) print('GET:', request.GET) print('body:', request.body) if request.method=='POST': data=request.body import json res=data.decode('utf-8') print(res,type(res)) res1=json.loads(res) print(res1,type(res1)) return HttpResponse(res1) return render(request,'jsonajax.html')
Ajax实现文件上传
1.利用一个js内置对象FormData
2.这个FormData即可以传普通的键值对也可以传文件
3.需要修改两个默认的参数processData,contentType
4.获取input框存储的文件数据$('input')[0].files[0]
def fileupload(request): if request.method=='POST': print(request.POST) print(request.FILES) return HttpResponse('收到了,小老弟') return render(request,'fileupload.html')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css"> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script> </head> <body> 文件上传:<input type="file" id="i1"> <button id="b1">点击提交</button> <script> $('#b1').click(function () { //传文件的时候在form表单中我们需要制定参数是formdata,在这里我们也要来一个formdata let formdata = new FormData(); // formData对象不仅可以传文件而且可以传普通的键值对 formdata.append('name','jason'); //获取input框存放的文件 //这里就用到了files这个方法,jquery是没有这个方法的,所以我们要先得到一个js对象 //$('#i1')[0].files[0] 是因为files里面有好多个文件,而我们只要第一个 formdata.append('myfile',$('#i1')[0].files[0]); $.ajax({ url:'', type:'post', data:formdata, //ajax发送文件需要修改两个固定的参数 processData:false, //告诉浏览器不要对数据进行处理 contentType:false, //告诉浏览器使用自带的formdata格式,不要编码 //回调函数 success:function (data) { alert(data) } }) }) </script> </body> </html>
总结:Ajax的特点是异步提交数据,产生局部刷新的效果,默认提交数据的方式是get提交,所以我们需要修改里面的type类型,然后我们还可以自定义FormData对象,Ajax也支持基于这个对象的大文件上传。
Ajax和form表单的区别:
1.form表单不支持异步提交局部刷新
2.form表单不支持传输json格式数据
3.form表单与Ajax默认传输数据的编码格式都是urlencoded
小结:基于现在所学,前端向后端发请求的方式有如下几种
1.浏览器窗口手动输入网址 get请求
2.a标签的href属性 get请求
3.form表单 get/post请求
4.Ajax get/post请求
其中,form表单和Ajax默认请求都是get
批量插入数据
当你打开一个页面的时候,想要直接插入100条数据到数据库,然后直接展示到前端页面上来,如何做到?那还不简单,我可以直接for循环100条数据,然后插入数据库,最后在从数据库中查出来展示,上代码!
def insernum(request): #动态插入100条数据 for i in range(100): models.Num.objects.create(name='第%s本书'%i) #查询所有的书籍展示到前端 book_list = models.Num.objects.all() return render(request,'num.html',locals())
但是,我们这样子做到话,效果真的超级超级的低,前端页面一直在等待我们数据的插入,虽然实现了数据的插入和展示,但是效率太低,那我们就得用到一个新的方法,我们先生成1000个数据对象,不走数据库,速度是很快的,然后将这1000个数据对象一次性插入,django支持我们这么做,用的是bulk_creat(),批量插入数据,见代码
def booklist(request): l=[] #数据太大的话,能不能做成生成器,每次只有一点**** for i in range(10000): l.append(models.Book2(name='第%s本书'%i)) 生成了一个对象 models.Book2.objects.bulk_create(l) 批量插入数据,速度超级快
g=(=models.Book2(name = '%s'%i)for i in range(100000000))***
models.Book2.objects.bulk_create(l)
自定义分页器
首先我们要先导入一个类,这个类可以帮我们实现分页的功能,将这个导入的文件放在utils里面,在下面新建一个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(''' <nav aria-label='Page navigation>' <ul class='pagination'> ''') first_page = '<li><a href="?page=%s">首页</a></li>' % (1) page_html_list.append(first_page) if self.current_page <= 1: prev_page = '<li class="disabled"><a href="#">上一页</a></li>' else: prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,) page_html_list.append(prev_page) for i in range(pager_start, pager_end): if i == self.current_page: temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,) else: temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,) page_html_list.append(temp) if self.current_page >= self.all_pager: next_page = '<li class="disabled"><a href="#">下一页</a></li>' else: next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,) page_html_list.append(next_page) last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,) page_html_list.append(last_page) # 尾部添加标签 page_html_list.append(''' </nav> </ul> ''') return ''.join(page_html_list)
然后我们直接导入使用就可以了
后端: 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] 前端:
1.将book_list全部替换册灰姑娘book_queryset
2.渲染分页器样式
{{ page_obj.page_html|safe }} # 帮你渲染的是带有bootstrap样式的分页器
django 自带的分页器,和我们差不多,就相当于每次手动写一遍
又是一个愉快的周末🙂🙂🙂