Ajax的简单使用介绍
一.多对多关系创建的三种方式
1)全自动(较为常用)
1 class Book(models.Model) 2 titile = models.CharField(max_length=32) 3 4 # 通过Django的ManyToManyField类方法快速创建第三张中间表 5 authors = models.ManyToManyField(to='author') 6 7 8 class Author(models.Model) 9 name = CharField(max_length=32)
-
优点:自动创建第三章表,快速
-
缺点:第三张表只有三个字段,无法添加其余的字段
1 class Book(models.Model) 2 titile = models.CharField(max_length=32) 3 4 5 6 class Author(models.Model) 7 name = CharField(max_length=32) 8 9 10 # 手动创建第三张表并添加外键关系 11 class Book2Author(models.Model) 12 book = models.ForeignKey(to='Book') 13 author=models.ForeignKey(to='Author') 14 create_time = models.DateField(auto_now_add=True)
-
优点:第三张表可以添加自己的扩展字段
-
缺点:orm查询的时候会带来不变
2)半自动(推荐使用)
1 class Book(models.Model) 2 titile = models.CharField(max_length=32) 3 # 需要建一个外键字段,额外添加两个参数,through表示通过那一张表来表示第三张表,through_field表示哪两个字段是用来链接的 4 authors = models.ManyToManyField(to='author',through=‘Book2Author’, through_fields=('book', 'author')) 5 6 7 class Author(models.Model) 8 name = CharField(max_length=32) 9 10 11 12 class Book2Author(models.Model) 13 book = models.ForeignKey(to='Book') 14 author=models.ForeignKey(to='Author') 15 create_time = models.DateField(auto_now_add=True)
-
优点:第三张表可以任意扩展额外的字段,还可以使用orm的正反向查询
-
缺点:无法利用add,set,remove,claer这些方法
虽然无法使用了 但是你还可以自己直接操作第三表
二.Ajax介绍
1)什么是Ajax?
AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)。
AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
简单概括就是:异步提交,局部刷新
-
同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
-
异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。任务的结果是是通过异步回调机制 callback()
-
与后端交互的方法:
交互方式 | 请求方式 |
---|---|
1.浏览器窗口输入回车 | get |
2.a标签href属性填写url点击 | get |
3.form表单 | get/post |
4.Ajax | get/post |
Ajax并不是一门新的语言 它其实就是基于js写的一个功能模块而已 由于原生js书写ajax较为繁琐 所以我们直接学jQuery封装号的ajax模块操作
2)Ajax的语法
举例:
需求:
1 # views.py 2 def index(request): 3 if request.method == 'POST': 4 i1 = request.POST.get('i1') 5 i2 = request.POST.get('i2') 6 # i1 和 i2 是字符串类型 需要先做类型转换 7 i3 = int(i1) + int(i2) 8 return HttpResponse(i3) 9 return render(request,'index.html') 10
1 # index.py 2 3 <input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3"> 4 <button id="d1">按钮</button> 5 <script> 6 //绑定事件 7 $('#d1').click(function () { 8 // 获取两个框里面内容 朝后端提交异步请求 9 // ajax基本语法 10 $.ajax({ 11 // 1.到底朝哪个后端提交数据 12 url:'', // 控制数据的提交路径 有三种写法 跟form表单的action属性一致 13 // 2.指定当前请求方式 14 type:'post', 15 // 3.提交的数据 16 data:{'i1':$('#i1').val(),'i2':$('#i2').val()}, 17 // 4.ajax是异步提交 所以需要给一个回调函数来处理返回的结果 18 success:function (data) { // data就是异步提交的返回结果 19 // 将异步回调的结果通过DOM操作渲染到第三个input框中 20 $('#i3').val(data) 21 } 22 }) 23 }) 24 </script>
3)前后端传输数据的编码格式
-
urlencoded
-
formdata
-
application/json
1).form表单提交的数据
默认是urlencoded编码格式传输数据 urlencoded数据格式:username=jason&password=123
1 # 简单代码 2 <form action="" method="post"> 3 <p></p> 4 <p></p> 5 <input type="text" name="username"> 6 <input type="text" name="password"> 7 <input type="submit" > 8
补充:django后端针对该格式的数据 会自动解析并帮你打包到request.POST中以键值对的形式存在
取出数据的方式:
if request.method == 'POST': print(request.POST) # <QueryDict: {'username': ['ajska'], 'password': ['123']}>
若再form表单中的enctype属性是以默认urlencoded格式,input中type属性是file格式,上传文件,只是上传的文件名,具体文件内容并没有上传上去,只有将格式改为form-data格式,通过request.files才能拿到最终数据,并且此时在网页中通过检查也无法轻易获取数据了
<form action="" method="post" enctype="multipart/form-data"> <input type="file" name="myfile">
formdata数据格式还是可以传普通送键值对数据 ,django后端针对符合urlencoded编码格式数据(普通键值对)还是统一解析到request.POST中 而针对formdata文件数据就会自动解析放到request.FILES中
2)ajax提交的数据
前后端数据交互 编码格式与数据格式一定要一致
-
默认也是urlnecoded编码格式
1 <script> 2 3 $('#d1').click(function () { 4 $.ajax({ 5 url:'', 6 type:'post', 7 data:{'username':'jason','password':123}, 8 success:function (data) { 9 alert(data) 10 } 11 }) 12 }) 13 </script>
-
但是Ajax也能发送application/json格式数据
1 $('#d2').on('click',function () { 2 $.ajax({ 3 url:'', 4 type:'post', 5 // 修改content-Type参数 6 contentType:'application/json',
//通过JSON.stringify出来成json格式 7 data:JSON.stringify({'username':'jason','password':123}), // 将数据序列化成json格式字符串 8 success:function (data) { 9 alert(data) 10 } 11 }) 12 })
此时后端无法拿到数据
1 def ab_ct(request): 2 if request.method == 'POST': 3 print(request.POST) 4 print(request.FILES)
数据已经传到requset.body中了
print(request.body)
这个数据既不在POST中,也不在FILES中,以json格式存在body中
我们可以自己解码反序列化拿到数据
1 # 自己处理json格式数据 2 json_bytes = request.body 3 # 先解码 4 json_str = json_bytes.decode('utf-8') 5 # 再反序列化 6 json_dict = json.loads(json_str) 7 #补充:json.loads能够自动解码并序列化 8 json_dict = json.loads(json_bytes) 9 print(json_dict,type(json_dict))
-
ajax也能提交文件格式
1 <input type="file" name="myfile" id="i1"> 2 <button id="d3">ajax发送文件数据</button> 3 <script> 4 $('#d3').click(function () { 5 // 1 需要先借助new方法生成一个内置对象 6 var myFormData = new FormData(); 7 // 2 传普通键值对 当普通键值对较多的时候 我们可以利用for循环来添加 8 myFormData.append('username','jason'); 9 myFormData.append('password',123); 10 // 3 传文件 11 myFormData.append('myfile',$('#i1')[0].files[0]); // 获取input框内部用户上传的文件对象 12 // 发送ajax请求 13 $.ajax({ 14 url:'', 15 type:'post', 16 data:myFormData, 17 // 发送formdata对象需要指定两个关键性的参数 18 19 processData:false, // 让浏览器不要对你的数据进行任何的操作 20 contentType:false, // 不要使用任何编码格式 对象formdata自带编码格式并且django能够识别该对象 21 22 success:function (data) { 23 alert(data) 24 } 25 }) 26 }) 27 </script>
28 def ab_ct(request): 29 if request.method == 'POST': 30 print(request.POST) 31 print(request.FILES) 32 return render(request,'ab_ct.html')
三.django内置序列化
举例:
1 def ab_se(request): 2 # 拿到所有数据库的对象集 3 user_queryset = models.Userinfo.objects.all() 4 user_list = [] 5 for user_obj in user_queryset: 6 user_list.append({ 7 'username':user_obj.username, 8 'password':user_obj.password, 9 'gender':user_obj.get_gender_display(), 10 }) 11 # 变成json格式 12 res = json.dumps(user_list) 13 return render(request,'ab_se.html',locals()) 14
<body>
{{ res }}
</body>
将数据库里面的数据通过json序列化 变成大字典的形式就是序列化
通过 http://www.bejson.com/ 这个网站可以在线校验
以上操作完全可以用Django的内置序列化模块 serializers处理,并且处理的更好
1 from app01 import models 2 from django.core import serializers 3 def ab_se(request): 4 user_queryset = models.Userinfo.objects.all() 5 # 传入需要修改的格式,以及需要序列化的对象集合 6 res = serializers.serialize('json',user_queryset) 7 return HttpResponse(res)
四:Django批量插入
1).普通批量插入
1 def ab_bc(request): 2 # 先插入1000条件数据 3 for i in range(1,1001): 4 models.Book.objects.create(title='第%s本书'%i) 5 book_queryset = models.Book.objects.all() 6 return render(request,'ab_bc.html',locals()) 7 </head> 8 <body> 9 {% for book_obj in page_queryset %} 10 <p>{{ book_obj.title }}</p> 11 {% endfor %} 12 </body>
2)快速批量插入
1 def ab_bc(request): 2 book_list = [] 3 for i in range(1,10001): 4 book_list.append(models.Book(title='新的%s书'%i)) 5 models.Book.objects.bulk_create(book_list) # 批量插入数据的方式 6 book_queryset = models.Book.objects.all() 7 return render(request,'ab_bc.html',locals()) 8 </head> 9 <body> 10 {% for book_obj in page_queryset %} 11 <p>{{ book_obj.title }}</p> 12 {% endfor %} 13 </body>
五.自定义分页器
分页器模板
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 class Pagination(object): 2 def __init__(self,current_page,all_count,per_page_num=2,pager_count=11): 3 """ 4 封装分页相关数据 5 :param current_page: 当前页 6 :param all_count: 数据库中的数据总条数 7 :param per_page_num: 每页显示的数据条数 8 :param pager_count: 最多显示的页码个数 9 10 用法: 11 queryset = model.objects.all() 12 page_obj = Pagination(current_page,all_count) 13 page_data = queryset[page_obj.start:page_obj.end] 14 获取数据用page_data而不再使用原始的queryset 15 获取前端分页样式用page_obj.page_html 16 """ 17 try: 18 current_page = int(current_page) 19 except Exception as e: 20 current_page = 1 21 22 if current_page <1: 23 current_page = 1 24 25 self.current_page = current_page 26 27 self.all_count = all_count 28 self.per_page_num = per_page_num 29 30 31 # 总页码 32 all_pager, tmp = divmod(all_count, per_page_num) 33 if tmp: 34 all_pager += 1 35 self.all_pager = all_pager 36 37 self.pager_count = pager_count 38 self.pager_count_half = int((pager_count - 1) / 2) 39 40 @property 41 def start(self): 42 return (self.current_page - 1) * self.per_page_num 43 44 @property 45 def end(self): 46 return self.current_page * self.per_page_num 47 48 def page_html(self): 49 # 如果总页码 < 11个: 50 if self.all_pager <= self.pager_count: 51 pager_start = 1 52 pager_end = self.all_pager + 1 53 # 总页码 > 11 54 else: 55 # 当前页如果<=页面上最多显示11/2个页码 56 if self.current_page <= self.pager_count_half: 57 pager_start = 1 58 pager_end = self.pager_count + 1 59 60 # 当前页大于5 61 else: 62 # 页码翻到最后 63 if (self.current_page + self.pager_count_half) > self.all_pager: 64 pager_end = self.all_pager + 1 65 pager_start = self.all_pager - self.pager_count + 1 66 else: 67 pager_start = self.current_page - self.pager_count_half 68 pager_end = self.current_page + self.pager_count_half + 1 69 70 page_html_list = [] 71 # 添加前面的nav和ul标签 72 page_html_list.append(''' 73 <nav aria-label='Page navigation>' 74 <ul class='pagination'> 75 ''') 76 first_page = '<li><a href="?page=%s">首页</a></li>' % (1) 77 page_html_list.append(first_page) 78 79 if self.current_page <= 1: 80 prev_page = '<li class="disabled"><a href="#">上一页</a></li>' 81 else: 82 prev_page = '<li><a href="?page=%s">上一页</a></li>' % (self.current_page - 1,) 83 84 page_html_list.append(prev_page) 85 86 for i in range(pager_start, pager_end): 87 if i == self.current_page: 88 temp = '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i,) 89 else: 90 temp = '<li><a href="?page=%s">%s</a></li>' % (i, i,) 91 page_html_list.append(temp) 92 93 if self.current_page >= self.all_pager: 94 next_page = '<li class="disabled"><a href="#">下一页</a></li>' 95 else: 96 next_page = '<li><a href="?page=%s">下一页</a></li>' % (self.current_page + 1,) 97 page_html_list.append(next_page) 98 99 last_page = '<li><a href="?page=%s">尾页</a></li>' % (self.all_pager,) 100 page_html_list.append(last_page) 101 # 尾部添加标签 102 page_html_list.append(''' 103 </nav> 104 </ul> 105 ''') 106 return ''.join(page_html_list)
使用方式
先在app01下面新建一个utils文件夹,并在其中建一个mypage.py文件,再将上面的模版复制进文件中
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 from app01.utils.mypage import Pagination 2 def ab_bc(request): 3 # 先插入1000条件数据 4 book_list = [] 5 for i in range(1,10001): 6 book_list.append(models.Book(title='新的%s书'%i)) 7 models.Book.objects.bulk_create(book_list) # 批量插入数据的方式 8 book_queryset = models.Book.o 9 # 获取当前页 10 current_page = request.GET.get('page', 1) 11 # 数据总条数 12 all_count = book_queryset.count() 13 # 1 现生成一个自定义分页器类对象 14 page_obj = Pagination(current_page=current_page,all_count=all_count,pager_count=9) 15 # 2 针对真实的queryset数据进行切片操作 16 page_queryset = book_queryset[page_obj.start:page_obj.end] 17 return render(request,'ab_bc.html',locals())bjects.all()
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <body> 2 {% for book_obj in page_queryset %} 3 <p>{{ book_obj.title }}</p> 4 {% endfor %} 5 <!--渲染页面--> 6 {{ page_obj.page_html|safe }} 7 </body> 8 </html>
六.Ajax结合sweetalert实现二次删除
前期准备: 下载项目文件
建立一个satatic文件夹将此文件导入,在html文件中导入文件路径
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 # views.py 2 3 from django.http import JsonResponse # 可以实现返回一个字典 4 import time 5 def show_user(request): 6 """ 7 前后端如果是通过ajax进行交互 那么交互的媒介一般情况下都是一个字典 8 :param request: 9 :return: 10 """ 11 if request.method == 'POST': 12 time.sleep(3) 13 14 back_dic = {"code":1000,'msg':''} 15 16 delete_id = request.POST.get('delete_id') 17 18 models.Userinfo.objects.filter(pk=delete_id).delete() 19 20 back_dic['msg'] = '删除成功,准备跑路!!!' 21 22 return JsonResponse(back_dic) 23 user_queryset = models.Userinfo.objects.all() 24 return render(request,'show_user.html',locals())
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> 7 <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> 8 <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> 9 {% load static %} 10 <link rel="stylesheet" href="{% static 'dist/sweetalert.css' %}"> 11 <script src="{% static 'dist/sweetalert.min.js' %}"></script> 12 <style> 13 div.sweet-alert h2 { 14 padding-top: 10px; 15 } 16 </style> 17 </head> 18 <body> 19 <div class="container"> 20 <div class="row"> 21 <div class="col-md-8 col-md-offset-2"> 22 <h2 class="text-center">数据展示</h2> 23 <table class="table-hover table table-striped"> 24 <thead> 25 <tr> 26 <th>主键</th> 27 <th>用户名</th> 28 <th>密码</th> 29 <th>性别</th> 30 <th>操作</th> 31 </tr> 32 </thead> 33 <tbody> 34 {% for user_obj in user_queryset %} 35 <tr> 36 <td>{{ user_obj.pk }}</td> 37 <td>{{ user_obj.username }}</td> 38 <td>{{ user_obj.password }}</td> 39 <td>{{ user_obj.get_gender_display }}</td> 40 <td> 41 <a href="#" class="btn btn-primary btn-xs">编辑</a> 42 <a href="#" class="btn btn-danger btn-xs cancel" data_id="{{ user_obj.pk }}">删除</a> 43 </td> 44 </tr> 45 {% endfor %} 46 </tbody> 47 48 </table> 49 </div> 50 </div> 51 </div> 52 53 54 <script> 55 $('.cancel').click(function () { 56 var $aEle = $(this); 57 swal({ 58 title: "你确定要删吗?", 59 text: "你如果删了,你可要准备跑路啊!", 60 type: "warning", 61 showCancelButton: true, 62 confirmButtonClass: "btn-danger", 63 confirmButtonText: "是的,老子就要删!", 64 cancelButtonText: "惹不起惹不起!", 65 closeOnConfirm: false, 66 closeOnCancel: false, 67 showLoaderOnConfirm: true 68 }, 69 function (isConfirm) { 70 if (isConfirm) { 71 // 发送ajax请求 72 $.ajax({ 73 url:'', 74 type:'post', 75 data:{'delete_id':$aEle.attr("data_id")}, 76 success:function (data) { // 回调函数会自动将二进制的json格式数据 解码并反序列成js中的数据类型 77 if (data.code == 1000){ 78 swal("删了!", "你准备跑路吧!", "success"); 79 // 方式1 80 {#window.location.reload()#} 81 // 方式2 DOM操作动态修改 82 $aEle.parent().parent().remove() // 将标签直接移除 83 }else{ 84 swal('发生了未知的错误', "error"); 85 } 86 } 87 }); 88 89 } else { 90 swal("怂笔", "你成功的刷新我对你的认知", "error"); 91 } 92 }); 93 }) 94 </script> 95 </body>