Ajax contentType
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互
Ajax是js中的技术,但原生的js操作Ajax比较复杂,我们这里为了提高效率,直接使用jQuery封装版本的Ajax
二.优点
1.Ajax向服务器发送异步请求 2.Ajax请求无序刷新整个页面(局部刷新) 3.因为服务器响应内容不再是整个页面,而是页面的局部内容没所以Ajax性能高 '''局部刷新,异步请求'''
三.如何使用
/*基本参数:*/ 1.url : 提交的地址 2.type : 提交的方式(默认GET) 3.data : 提交的数据 4.success : 回调函数(因为是异步提交,需要回调函数,取结果)
/*基本语法:*/ Ajax通常与事件绑定使用 $('#d1').click(function() { $.ajax({ url:'/index/', // 提交的地址 type:'post', // 提交的方式 data:{'name':'xionger', 'password':'123'} // 提交的数据 success:function(data) { alert(data) // data接收的就是异步提交返回的结果 } }) })
求和实例:
<!--前端--> <body> <input type="text" id="id1"> + <input type="text" id="id2"> = <input type="text" id="id3"> <button id="b1">求和</button> <script> $('#b1').click(function () { $.ajax({ url:'', type:'post', data:{'id1':$('#id1').val(),'id2':$('#id2').val()}, success:function (data) { // {alert(data)} data形参用来接收异步提交的结果 $('#id3').val(data) // 通过DOM操作,将结果渲染到第三个input框中 } }) }) </script> </body>
# 后端 def index(request): if request.is_ajax(): # 判断是否是Ajax if request.method == 'POST': # POST 方式请求的数据都在POST中 id1 = request.POST.get('id1') id2 = request.POST.get('id2') # 数据传输过来d都是字符串,强转整型 id1 = int(id1) id2 = int(id2) res = id1 + id2 # 将结果返回到前端 return HttpResponse(res) return render(request, 'index.html')
contentType
一.前后端传输数据编码格式
1.urlencoded # form表单与Ajax默认的数据编码格式 2.formdata # form表单 3. json # Ajax ps: Ajax传输文件建议使用内置对象: new Formdata() '''注意:前后端传输数据的时候,一定要保证数据格式和你的编码格式是一致的'''
1.urlencoded
1.数据格式: name=xionger&password=123
2.Django后端针对urlencoded编码格式的数据会自动解析并放到 request.POST 中.
3.form表单与Ajax默认的数据编码格式
2.formdata
1.form表单传输文件的编码格式 2.Django后端针对form表单指定formdata格式传输文件就会自动解析并将文件放到request.FILES中 3.使用:<form action="" method="post" enctype="multipart/form-data">
3.json
1.Ajax发送json格式数据 2.Django后端针对json格式的数据,并不会自动解析放到request.POST或者request.FILES里面,
它并不会解析json格式数据,而是将它原封不动的放在request.body中 3.使用:data:JSOM.stringify({'name':'xionger', 'password':123}) ps:JSOM.stringify() 类似 json.dumps()
前后端传输数据的编码方式 1.urlencoded >>> name=jason&pwd=123&hobby=read 2.formdata >>> 传文件也支持传普通键值(name=jason&pwd=123&hobby=read) 3.application/json >>> json格式数据(form表单是无法发送json格式数据的) form,ajax默认的是urlencoded django后端针对不同的编码格式是如何处理的? 只要是符合urlencoded编码格式 都会被后端自动获取并解析放到request.POST中 如果是符合formdata那么文件会自动被解析放到request.FILES中 如果是json格式 后端默认不解析 以二进制的形式就放在request.body你可以自己手动处理即可
二.Ajax发送json格式与文件实例
1.发送json格式数据
<!--前端--> <body> <input type="text" id="name" > <input type="text" id="pwd" > <button id="b1">登录</button> <script> $('#b1').click(function () { $.ajax({ url:'', type:'post', data:JSON.stringify({'id1':$('#name').val(),'id2':$('#pwd').val()}), contentType:'application/json', // 告诉后端传世的数据时json格式 success:function (data) { {alert(data)} // data形参用来接收异步提交的结果 $('#id3').val(data) // 通过DOM操作,将结果渲染到第三个input框中 } }) }) </script> </body>
# 后端 import json def login(request): if request.is_ajax(): # 判断是否是Ajax if request.method == 'POST': json_bytes = request.body # 前端json格式传输的数据都在request.body中 # 在request.body中,json格式的数据没有任何处理,是二进制形式,需要后端反序列化 print(json.loads(json_bytes)) # {'id1': 'xionger', 'id2': '123'} name = json.loads(json_bytes).get('name') password = json.loads(json_bytes).get('pwd') print(name) # xionger print(password) # 123 # 将结果返回到前端 return HttpResponse('OK') return render(request, 'ajax_json.html')
发送文件
# 如何获取文件标签所存储的文件对象? 固定语法: 1.先用jQery查找到存储文件的input标签 2.将jQuery对象转成原生js对象 3.利用原生js对象的方法 $('input')[0].files[0]获取到标签内部存储的文件对象 4.一定要指定两个参数都为false # ajax发送文件需要指定两个额外的参数 1.processData:false, # 告诉前端不要处理数据 2.contentType:false, # 不适用任何编码 因为formdata对象自身自带编码django后端也能够识别formdata对象
1.利用内置对象FormData 既可以传文件也可以传普通的键值对 2.获取input标签存储的文件对象 先用jQuery找到该input标签,然后转成原生的js对象 然后固定语法.files[0] $('input')[0].files[0] 3.发送ajax请求 有两个关键性的参数需要你指定 processData:false contentType:false django后端就会普通的键值解析到request.POST中文件解析到request.FILES
<body> <script> $('#b1').on('click',function () { // ajax传输文件 建议使用内置对象formdata var formData = new FormData(); // 既可以传普通的键值对 也可以传文件 // 添加普通键值 formData.append('username','jason'); formData.append('password','123'); // 传文件 // 如何获取文件标签所存储的文件对象? 固定语法 // 1.先用jQery查找到存储文件的input标签 // 2.将jQuery对象转成原生js对象 // 3.利用原生js对象的方法 .files[0]获取到标签内部存储的文件对象 // 4.一定要指定两个参数都为false formData.append('my_file',$('#d1')[0].files[0]); $.ajax({ url:'', // 控制发送给谁 不写就是朝当前地址提交 type:'post', // 发送方式是post请求 data:formData, // 发送的数据 // ajax发送文件需要指定两个额外的参数 processData:false, // 告诉前端不要处理数据 contentType:false, // 不适用任何编码 因为formdata对象自身自带编码 django后端也能够识别formdata对象 success:function (data) { // data形参用来接收异步提交的结果 {alert(data)} $('#i3').val(data) } }) }) </script> </body>
Ajax删除按钮实例
利用ajax删除实例
<!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> {% load static %} <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}"> <link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}"> <script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script> <script src="{% static 'dist/sweetalert.min.js' %}"></script> <style> div.sweet-alert h2{ padding-top: 10px; } </style> </head> <body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> <h2 class="text-center">数据展示</h2> <table class="table-striped table table-hover table-bordered"> <thead> <tr> <th>序号</th> <th>主键</th> <th>用户名</th> <th>年龄</th> <th>性别</th> <th>操作</th> </tr> </thead> <tbody> {% for user in user_list %} <tr> <td>{{ forloop.counter }}</td> <td>{{ user.pk }}</td> <td>{{ user.username }}</td> <td>{{ user.age }}</td> <td>{{ user.get_gender_display }}</td> <td> <button class="btn btn-primary btn-sm">编辑</button> <button class="btn btn-danger btn-sm del" user_id="{{ user.pk }}">删除</button> </td> </tr> {% endfor %} </tbody> </table> </div> </div> </div> <script> $('.del').click(function () { // 获取当前标签对象 var $btnEle = $(this); swal({ title: "你确定要删吗?", text: "你要是删了,你就准备跑路吧!", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "是的,老子就要删!", cancelButtonText: "算了,算了!", closeOnConfirm: false, showLoaderOnConfirm: true }, function(){ // 朝后端发送ajax请求 $.ajax({ url:'', type:'post', data:{'delete_id':$btnEle.attr('user_id')}, success:function (data) { // 后端发字典过来 前端不需要你手动转 会自动帮你转换成js自定义对象 if (data.code == 100){ {#window.location.href = ''; // 不写就是跳到当前页面#} // 通过DOM操作 实时改变页面 // 将被点击的删除按钮所在的那一行直接从DOM树中删掉 $btnEle.parent().parent().remove(); swal("删掉了!", "赶紧回去收拾行李吧,准备跑路!", "success"); }else{ swal('发生了未知的错误','估计是有bug了','info') } } }); }); }) </script> </body> </html>
class User(models.Model): username = models.CharField(max_length=32) age = models.CharField(max_length=32) choices = ( (1,'男'),(2,'女'),(3,'其他') ) gender = models.IntegerField(choices=choices) """ 1 存choice里面罗列的数字与中文对应关系 print(user_obj.get_gender_display()) 只要是choices字段 在获取数字对应的注释 固定语法 get_choices字段名_display() 2 存没有罗列迟来的数字 不会报错 还是展示数字 """
from app01 import models from django.http import JsonResponse def userlist(request): if request.is_ajax(): """ 一般情况下 针对ajax请求 后端通常都是返回一个字典 """ back_dic = {'code':100, 'msg':''} # code用于前端校验是否删除成功 # 拿到指定删除对象的id delete_id = request.POST.get('delete_id') models.User.objects.filter(pk=delete_id).delete() # 给前端ajax返回一个消息字典 back_dic['msg'] = '删除成功' return JsonResponse(back_dic) user_list = models.User.objects.all() return render(request, 'userlist.html',locals())
分页器
<!--前端--> {% for book in page_queryset %} <p>{{ book.title }}</p> {% endfor %} {{ page_obj.page_html|safe }}
# 后端 book_list = models.Book.objects.all() current_page = request.GET.get("page",1) all_count = book_list.count() page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10,pager_count=5) page_queryset = book_list[page_obj.start:page_obj.end]
分页器模板代码
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)
from app01.utils.mypage import Pagination def book(request): book_list = models.Book.objects.all() current_page = request.GET.get("page",1) all_count = book_list.count() page_obj = Pagination(current_page=current_page,all_count=all_count,per_page_num=10) page_queryset = book_list[page_obj.start:page_obj.end] return render(request,'booklist.html',locals())
<body> <div class="container"> <div class="row"> <div class="col-md-8 col-md-offset-2"> {% for book in page_queryset %} <p>{{ book.title }}</p> {% endfor %} {{ page_obj.page_html|safe }} </div> </div> </div> </body>
补充
Django 序列化组件
什么时候用
后端想直接将实例化出来的数据对象直接发送给客户端,那么这个时候,就可以用Django给我们提供的序列化方式
# 后端: def ser(request): #拿到用户表里面的所有的用户对象 user_list=models.User.objects.all() #导入内置序列化模块 from django.core import serializers #调用该模块下的方法,第一个参数是你想以什么样的方式序列化你的数据 ret=serializers.serialize('json',user_list) return render(request,'index.html',locals()) # 前端得到: [{"model": "app01.user","pk": 1,"fields": {"username": "jason","age": 18,"gender": 1} }......]
bulk_create 批量插入数据(高效)
l = [] for i in range(10000): l.append(models.Book2(name='第%s本书'%i)) models.Book2.objects.bulk_create(l) # 批量插入数据
choices字段参数
为什么用
1.对于类型性别,假否,婚否的字段,有固定字段数据的字段可以用choices参数
2.节省空间,因为存的是数字
如何使用
# models.py文件中: class User(models.Model): username = models.CharField(max_length=32) age = models.IntegerField() choices = ( (1,'男'),(2,'女'),(3,'其他') ) gender = models.IntegerField(choices=choices) # 指定choices参数 """ 1 存choice里面罗列的数字与中文对应关系 print(user_obj.get_gender_display()) 只要是choices字段 在获取数字对应的注释 固定语法 get_字段名_display() 2 存没有罗列出来的数字 不会报错 还是展示数字 """
# views.py文件中 def userlist(request): user_obj = models.User.objects.filter(pk=1).first() gender = user_obj.get_gender_display() # 得到对应的性别注释,如'男'