10-7,Django_Learn之Ajax

Posted 吴平凡

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了10-7,Django_Learn之Ajax相关的知识,希望对你有一定的参考价值。

7 Ajax

7.1 Ajax简介

  • 异步提交,局部刷新

  • 其最大优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。

例子:GitHub注册,动态获取用户名实时跟后端确认并实时展示的前端(局部刷新)

  • 向后端发送请求的方式:

浏览器地址输入url回车    GET请求a标签herf属性           GET请求form表单                GET/POST请求ajax                    GET/POST请求

只学习jQuery封装之后的版本(不学原生,复杂且一般不用),所以使用ajax时需要确保导入了jquery。ps:并不只有jQuery能实现ajax,其他的框架也可以,换汤不换药。

例:描述:页面上有三个input框,在前面两个框中输入数字点击按钮,朝后端发送ajax请求,后端计算出结果,在返回给前端动态展示的第三个框中(整个过程页面不准有刷新,也不能在前端计算)
views.py
def ab_ajax(request): if request.method == 'POST': # print(request.POST) # <QueryDict: {'username': ['Jack'], 'password': ['123']}> # <QueryDict: {'i1': ['111'], 'i2': ['222']}> i1 = request.POST.get('i1') i2 = request.POST.get('i2') # # # 先转型再加 i3 = int(i1) + int(i2) # print(i3) # d = {'code':100,'msg':i3} # d = {'code':100,'msg':666} return HttpResponse(i3) # return HttpResponse(d) # return HttpResponse(json.dumps(d)) # return JsonResponse(d) return render(request, 'ab_ajax.html')
ab_ajax.html
<input type="text" id="d1"> +<input type="text" id="d2"> =<input type="text" id="d3"><br/><br/><p> <button id="btn">点我</button></p><script> // 先给按钮绑定一个点击事件 $('#btn').click(function () { //朝后端发送ajax请求 $.ajax({ //1,指定朝哪个后端发送ajax请求 url: '',// 不写就是向当前地址提交 //2,请求方式 type: 'post',//不指定默认是get请求 //3,数据 {#data:{'username':'Jack','age':23},#} data: {'i1': $('#d1').val(), 'i2': $('#d2').val()}, //4,回调函数(异步回调机制):当后端返回结果时自动触发 args接收返回的结果 {#dataType:true, //会自动反序列化#} success: function (args) { {#alert(args) // 通过DOM操作动态渲染到第三个input里面#} $('#d3').val(args) {#console.log(typeof args)#} } }) })</script>

此时运行之后有

10-7,Django_Learn之Ajax

"""后端如果是用HttpResponse返回的数据,回调函数不会自动反序列化如果后端用的是JsonResponse返回的数据,回调函数会自动反序列化就是想用HttpResponse方法: 1,在前端利用JSON.parse() 2,在ajax里配置一个参数"""

7.2 前后端传输数据的编码格式(contentType)(了解)

  • 主要post请求数据的编码格式

get请求数据就是直接在url后面
  • 可以向后端发送post请求的方式

form表单、ajax请求、
  • 前后端传输数据的三种格式

urlencode,formdata,json
views.py
def index(request): if request.method == "POST": print(request.POST) print(request.FILES) return render(request, 'index.html')
index.html
<form action="" method="post" enctype="multipart/form-data">{#<form action="" method="post">#} <p>username:<input type="text" name="username" class="form-control"></p> <p>password:<input type="text" name="password" class="form-control"></p> <p>file:<input type="file" name="file"></p> <input type="submit" class="btn btn-success"> <input type="button" class="btn btn-danger" value="按钮" id="d1"></form>
7.2.1 研究form表单
默认编码格式是urlencoded,格式为:username=root&password=123
django客户端针对符合urlencoded编码格式的数据会自动解析封装到request.POST中, username=root&password=123 >>> r equest.POST

10-7,Django_Learn之Ajax

如果把编 码格式改成formdata, 则针对普通的键值对还是 解析到 request.POST中,而文件解析到request.FILES中。

10-7,Django_Learn之Ajax

form表 单没有办法发送json格式数据
7.2.2 研究ajax
index.html添加如下代码进行测试
<script> $('#d1').click(function () { $.ajax({ url:'', type:'post', data:{'username':'Jack','age':23}, success:function (args) {               } }) })</script>
默认编码格式是urlencoded,格式为:username=root&password=123
django客户端针对符合urlencoded编码格式的数据会自动解析封装到request.POST
username=Jack&age=23 >>> request.POST

7.3 ajax发送json格式数据

  • 前后端传输数据是一定要确保编码格式跟数据真正的格式是一致的

{"username":"Jack","age":23} 在request.POST肯定找不到
  • request对象方法补充

request.is_ajax()判断是否是ajax请求 返回布尔值
django针对json格式的数据不做任何处理

views.py

import json def ab_json(request): if request.is_ajax(): # print(request.is_ajax()) # True # print(request.POST) # <QueryDict: {}> # print(request.FILES) # <MultiValueDict: {}> # print(request.body) # b'{"username":"Jack","age":23}' # 针对json格式数据需要手动处理 json_bytes = request.body # json_str = json_bytes.decode('utf-8') # json_dict = json.loads(json_str) # print(json_dict,type(json_dict)) # {'username': 'Jack', 'age': 23} <class 'dict'>  # json.loads()括号内若传入了一个二进制格式的数据则内部会自动解码在反序列化 json_dict = json.loads(json_bytes) print(json_dict, type(json_dict)) # {'username': 'Jack', 'age': 23} <class 'dict'> return render(request, 'ab_json.html')

ab_json.html

<button class="btn btn-danger" id="d1">点我</button>
<script> $('#d1').click(function () { $.ajax({ url:'', type:'post', {#data:{'username':'Jack','age':23},//此格式会报错#} data:JSON.stringify({'username':'Jack','age':23}),//转成json格式 contentType:'application/json',//指定编码格式 success:function () {
} }) })</script>

点击之后有

10-7,Django_Learn之Ajax

  • ajax发送json数据需要注意

1,contentType参数指定为application/json
2,数据是真正的json格式数据
3,django后端不会处理json格式数据,需要手动去request.body获取并处理

7.4 ajax发送文件

借助于js内置对象FormData

views.py

def ab_file(request): if request.is_ajax(): if request.method == "POST": print(request.POST) print(request.FILES)
return render(request, 'ab_file.html')

ab_file.html

<p>username:<input type="text" id="d1"></p><p>password:<input type="text" id="d2"></p><p><input type="file" id="d3"></p><button class="btn btn-info" id="d4">点我</button>
<script> //向后端发送普通键值对和文件数据 $('#d4').on('click', function () { // 1 需要先利用FormData内置对象 let formDataObj = new FormData(); // 2 添加普通键值对 formDataObj.append('username', $('#d1').val()) formDataObj.append('password', $('#d2').val()) // 3 添加文件对象 formDataObj.append('myfile', $('#d3')[0].files[0]) // 4 将对象基于ajax发送给后端 $.ajax({ url: '', type: 'post', data: formDataObj,// 直接将对象放在data后面即可 // ajax 发送文件必须指定的两个参数 contentType: false,// 不需要使用任何编码,django后端可以自动识别formData对象 processData: false,// 告诉浏览器不要对数据做任何处理 sucess: function (args) {
} }) })</script>

运行点击之后

10-7,Django_Learn之Ajax

10-7,Django_Learn之Ajax

  • 总结:

1,需要利用内置对象
2,需要指定两个关键性参数
3,django后端可以自动识别formData对象且能将内部的普通键值自动解析 并封装到request.POST中,文件数据自动解析并封装到request.FILES中。

7.5 django自带的序列化组件(drf铺垫)

需求:在前端获取到后端用户列表里所有的数据,且是列表套字典格式

views.py

import jsonfrom django.core import serializers
def ab_ser(request): user_queryset = models.User.objects.all()
# return render(request,'ab_ser.html',locals()) # [{},{},{},...] # user_list = [] # for user_obj in user_queryset: # tmp = { # 'pk': user_obj.pk, # 'name': user_obj.name, # 'age': user_obj.age, # 'gender': user_obj.get_gender_display() # } # user_list.append(tmp) # return JsonResponse(user_list, safe=False) ''' [{ "pk": 1, "name": "Jack", "age": 20, "gender": "male" }, { "pk": 2, "name": "Amy", "age": 15, "gender": "female" }, { "pk": 3, "name": "Bob", "age": 30, "gender": "male" }, { "pk": 4, "name": "Sum", "age": 40, "gender": "male" } ]
前后端分离的 作为后端只需要写代码将数据处理好能够序列化返回给前端即可        再写一个接口文档,告诉前端每个字段代表的意思即可    ''' # 序列化 res = serializers.serialize('json', user_queryset) """会自动将数据变成json格式的字符串,且内部非常全面"""    return HttpResponse(res)    """[{ "model": "app01.user", "pk": 1, "fields": { "name": "Jack", "age": 20, "gender": 1 }}, { "model": "app01.user", "pk": 2, "fields": { "name": "Amy", "age": 15, "gender": 2 }}, { "model": "app01.user", "pk": 3, "fields": { "name": "Bob", "age": 30, "gender": 1 }}, { "model": "app01.user", "pk": 4, "fields": { "name": "Sum", "age": 40, "gender": 1 }}]
写接口就是利用序列化组件渲染数据然后写一个接口文档,该交代交代一下"""

ab_ser.html

{% for user_obj in user_queryset %}<p>{{ user_obj }}</p>{% endfor %}

7.6 ajax结合sweetalert

  • 要学会如何拷贝

  • 学会基于别人的基础之上做修改

  • 研究各个参数表示的意思,然后照葫芦画瓢

sweetalert部分源码取自http://mishengqiang.com/sweetalert/(还需要引用其css和js代码)。

后端:

import time

def user_list(request): user_queryset = models.User.objects.all() return render(request, 'user_list.html', locals())

def delete_user(request): """ 前后端在用ajax进行交互的时候,后端通常给ajax的回调函数返回一个字典格式的数据 """ if request.is_ajax(): if request.method == "POST": back_dic = {'code': 1000, 'msg': ''} time.sleep(3) # 模拟操作数据的延迟 delete_id = request.POST.get('delete_id') models.User.objects.filter(pk=delete_id).delete() # 需要告诉前端操作的结果 back_dic['msg'] = '数据已经删了,你赶紧跑路吧' return JsonResponse(back_dic)

前端:

<div class="container-fluid"> <h1 class="text-center">用户展示</h1> <div class="row"> <div class="col-md-8 col-md-offset-2"> <table class="table table-hover table-striped"> <thead> <tr> <th>ID</th> <th>name</th> <th>age</th> <th>gender</th> <th>actions</th> </tr> </thead> {% for user_obj in user_queryset %} <tbody> <tr> <td>{{ forloop.counter }}</td> <td>{{ user_obj.name }}</td> <td>{{ user_obj.age }}</td> <td>{{ user_obj.get_gender_display }}</td> <td> <button class="btn btn-warning btn-xs">编辑</button> <button class="btn btn-danger btn-xs del" delete_id="{{ user_obj.pk }}">删除</button> <!--因为其在循环中,所以不能直接加id,需要添加class--> </td> </tr> </tbody> {% endfor %} </table> </div>    </div></div>
<script> $('.del').on('click', function () { //先将当前标签对象存储起来 let currentBtn = $(this); // alert(123) // alert($(this).attr('delete_id')) // 二次确认弹框 swal({ title: "确定删除吗?", text: "你可要考虑清楚了,可能需要拎包跑路额", type: "warning", showCancelButton: true, confirmButtonColor: "#DD6B55", confirmButtonText: "是的,老子就要删", cancelButtonText: "算了,算了!", closeOnConfirm: false, closeOnCancel: false, // showLoaderOnConfirm: true }, function (isConfirm) { if (isConfirm) { // 向后端发送ajax请求删除数据后 再弹框 $.ajax({ // url:'/delete/user/'+currentBtn.attr('delete_id'),//1 传递主键值方式1 url: '/delete/user/', // 2 放在请求体里 type: 'post', data: {'delete_id': currentBtn.attr('delete_id')}, success: function (args) { // args = {'code':'','msg':''} // 判断响应状态码,然后做不同处理 if (args.code === 1000) { swal('删了', args.msg, 'sucess') // 1 lowb版本 直接刷新当前页面 // window.location.reload() // 2 利用DOM操作动态刷新 currentBtn.parent().parent().remove() } else { swal('完了', '出现了未知的错误', 'info') } }                    }) swal("删除!", "赶紧跑路吧。", "success"); } else { swal("怂逼", "不要说我认识你", "error"); } }); })</script>

7.7 批量插入

  • 普通版(耗时较长)

views.py

def ab_pl(request):# 先给book插入300条数据for i in range(300): models.Book.objects.create(title="第%s本书"%i)# 再讲所有的数据查询并展示到页面 book_queryset = models.Book.objects.all()return render(request,'ab_pl.html',locals())#耗时较长

ab_pl.html

{% for book_obj in page_queryset %}    <p>{{ book_obj.title }}</p>{% endfor %}
  • 有批量插入版(bulk_create

 # 批量插入 book_list = [] for i in range(300): book_obj = models.Book(title="第%s本书"%i) book_list.append(book_obj) models.Book.objects.bulk_create(book_list)    book_queryset = models.Book.objects.all() """ 当批量插入数据时,使用orm提供的bulk_create能够大大减少操作时间 """

速度提升明显。

7.8 分页器

注:制作页码时一般都是奇数个,符合国人对对称美的标准

  • 分页器推导

 # 分页 book_list = models.Book.objects.all() # 要访问哪一页 current_page = request.GET.get('page',1) # 若获取不到当前页码,就展示第一页 # 数据类型转换 try: current_page = int(current_page) except Exception: current_page = 1 # 每页展示多少条 per_page_num = 10 # 起始位置 start_page = (current_page-1) * per_page_num #终止位置    end_page = current_page * per_page_num book_queryset = models.Book.objects.all()[start_page:end_page]
return render(request,'ab_fenye.html',locals())

运行,取bootstrap中的分页代码粘贴到html文件中,在浏览器输入相关网址可以得到

10-7,Django_Learn之Ajax

在程序中再添加

 # 计算总共有多少页 all_count = book_list.count() page_count, more = divmod(all_count, per_page_num) if more: page_count += 1     # 前端html文件中没有range方法,故将前端分页代码放在此处 page_html = '' for i in range(1,page_count+1): page_html += '<li><a href="?page=%s">%s</a></li>' % (i, i) book_queryset = book_list[start_page:end_page] return render(request, 'ab_pl.html', locals())

html文件代码改为

{% for foo in book_queryset %}<p>{{ foo.title }}</p>{% endfor %}<nav aria-label="Page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">&laquo;</span> </a> </li> {{ page_html|safe }} <li> <a href="#" aria-label="Next"> <span aria-hidden="true">&raquo;</span> </a> </li> </ul></nav>

则有

10-7,Django_Learn之Ajax

再对函数进行调整

 xxx = current_page if current_page < 6: current_page = 6
for i in range(current_page - 5, current_page + 6): if xxx == i: page_html += '<li class="active"><a href="?page=%s">%s</a></li>' % (i, i)# 高亮显示 else: page_html += '<li><a href="?page=%s">%s</a></li>' % (i, i)

则可以得到

django中有自带的分页模块,但是书写起来比较麻烦且功能太简单,故可自定义分页器。上述代码知道内部逻辑即可,无需掌握
可封装自定义分页器:
https://www.cnblogs.com/Dominic-Ji/articles/12035722.html

7.9 自定义分页器的拷贝及使用

  • 当需要使用到非django内置的第三方功能或者组件代码时,一般会创建一个名为utils的文件夹,在该文件夹内对模块进行功能性划分

  • 后期封装代码时,不再局限于函数,而是尽量使用面向对象封装

后端:

from utils.mypage import Pagination
def ab_pl(request): book_queryset = models.Book.objects.all() current_page = request.GET.get('page', 1) all_count = book_queryset.count() # 1 传值生成对象 page_obj = Pagination(current_page=current_page, all_count=all_count) # 2 直接对总数据进行切片操作 page_queryset = book_queryset[page_obj.start:page_obj.end] # 3 将page_queryset传递到页面,替换之前的book_queryset return render(request, 'ab_pl.html', locals())

前端

{% for book_obj in page_queryset %} <p>{{ book_obj.title }}</p> <nav aria-label="Page navigation">    </nav>{% endfor %}{#利用自定义分页器直接显示分页器样式#}{{ page_obj.page_html|safe }}

运行有

具体代码详见:
https://gitee.com/damoguyan666/django_study
本号所写文章除特殊申明外所有资源来源于网络,仅用于个人学习参考之用,如有侵权请联系本人删除。

以上是关于10-7,Django_Learn之Ajax的主要内容,如果未能解决你的问题,请参考以下文章

Json与Ajax交互报错解决No converter found for return value of type: class com.github.pagehelper.PageInfo(代码片

Json与Ajax交互报错解决No converter found for return value of type: class com.github.pagehelper.PageInfo(代码片

python的django环境安装

Chrome读取XML一片空白,怎么处理

ajax获取后台数据渲染(整片文章不分段落)解决方案,要使用htmL方式输出

java并发编程之上下文切换等并发编程的挑战