Django框架第九篇--Django和Ajax、序列化组件(serializers)、自定义分页器、模型表choice参数
Django和Ajax
一、什么是Ajax
AJAXAsynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互,传输的数据为XML(当然,传输的数据不只是XML)
AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
- 同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;
- 异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。
二、Ajax的优点
优点:
- AJAX使用JavaScript技术向服务器发送异步请求;
- AJAX请求无须刷新整个页面;
- 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;
两个关键点:1.局部刷新,2.异步请求
三、基于jQuery实现的Ajax
1.基本语法
// 在html script中使用 $.ajax({ url:'/index/', //提交数据路径,不写默认是当前路径 type:'post', //标定ajax的请求方式 data:{'name':'lqz','age':18}, //data后面跟的就是你提交给后端的数据 //success为回调函数 success:function (data) { //data即后端给你返回的数据 alert(data) } })
2.利用ajax提交表单中的数据 (数字的相加例子)
index.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> </head> <body> <input type="text" id="i1">+<input type="text" id="i2">=<input type="text" id="i3"> <button class="btn btn-primary" id="d1" >求和</button> <script> //绑定点击事件 $('#d1').click(function () { //ajax写法 $.ajax({ url:'/index/' , type:'post', //设置发送方式是post请求 //获取两个输入框的值 data:{'i1':$('#i1').val(),'i2':$('#i2').val()}, //data是提交给后端的数据 //success回调函数 success:function (data) { //data是后端返回的数据 $('#i3').val(data) } }) }) </script> </body> </html>
views.py
def index(request): # print(request.is_ajax()) # 用来判断当前请求方式是否是ajax请求 if request.is_ajax(): if request.method == 'POST': # print(request.POST) #i1和i2是ajax传递过来的data字典键 i1 = request.POST.get('i1') i2 = request.POST.get('i2') # 后端获取的前端数据 都是字符串格式 res = int(i1) + int(i2) return HttpResponse(res) #返回给ajax return render(request,'index.html')
需要注意的
1.在设置ajax的url路径的时候,不写就是朝当前地址提交数据,如果你写了要注意路径格式,比如是这样('/index/') 2.type是设置ajax的请求方式,如果你写的是post,views视图就是通过request.POST.get获取数据,如果type是get请求方式,
就是通过request.GET.get获取数据。type值为空时,默认是get方法
四、form表单和ajax进行文件上传
1.contentType前后端传输数据编码格式
前后端传输数据编码格式
- urlencoded
- formdata
- json
2.form表单和ajax上传文件区别
form表单
1.默认使用的编码格式是urlencoded 数据格式:name = jason&pwd=123 django后端针对urlencoded编码格式的数据会自动解析并放在request.POST中供用户获取。 2.可以修改formdata传文件 django后端针对formdata编码格式的数据会自动解析并放在request.FILES中供用户获取。
注意:前后端传输数据的时候一定要保证数据格式和你的编码格式是一致的
模板层
<!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> </head> <body> <form action="" enctype="multipart/form-data" method="post"> <input type="text" name="name" id="name"> <input type="file" name="myfile" id="myfile"> <input type='submit' value = 'form表单上传文件'> //form表单上传文件格式 </form> <button id="btn">ajax提交文件</button> //ajax上传文件格式,触发下面的ajax <script> //绑定提交按钮 $('#btn').click(function () { //上传文件,建议使用Formdata var formdata =new FormData(); //既可以传普通键值对,也可以传文件 //添加普通键值对 formdata.append('name',$('#name').val()); //传文件,$('#myfile')[0].files拿到的是文件列表,取第0个把具体文件拿出来 formdata.append('myfile',$('#myfile')[0].files[0]); $.ajax({ url:'', type:'post', data:formdata, processData:false, //告诉前端不要处理数据 contentType:false, //不适用任何编码,因为formdata对象自带编码,django后端也能够识别formdata对象 success:function (data) { //后端返回给前端信息 alter(data) } }) }) </script> </body> </html>
视图层
#forms表单上传文件 def home(request): if request.method == 'GET': //渲染页面 return render(request,'home.html') #获取文件信息 myfile = request.FILES.get('myfile') //获取form表单上传的文件 print(myfile) //上传文件名 return HttpResponse('ok') #ajax上传文件 def home_ajax(request): if request.is_ajax(): if request.method == 'POST': name = request.POST.get('name') print(name) #input框内容 myfile = request.FILES.get('myfile') print(myfile) #文件名 print(myfile.name) #文件名 return HttpResponse('ok') return render(request,'home.html')
路由层
url(r'^home/',views.home,name='home'), //form表单上传文件 url(r'^home_ajax/',views.home_ajax,name='home_ajax'), //ajax上传文件
注意点
1.form表单上传文件需要指定编码格式enctype = 'multipart/form-data'。ajax也需要设置一样的编码格式,然后需要创建一个Formdata对象 获取file文件的内容都是通过request.FILES.get() 2.通过append的方法,给对象传值,相当于设置了一个个的键值对。 3.必须要设置这两个参数 processData:false contentType:false
五、基于ajax提交json格式数据
1.ajax提交数据
ajax默认数据提交方式也是urlencoded
ajax发送json格式数据
django后端针对json格式的数据 并不会自动解析放到request.POST或者request.FILES里面
它并不会解析json格式数据 而是将它原封不动的放在request.body中了
模板层
<!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>
</head>
<body>
<input type="text" name="name" id="d1">
<input type="password" name="password" id="d2">
<button id="d3">ajax提交json格式数据</button>
</body>
<script>
$('#d3').click(function () {
var pos_data = {'name':$('#d1').val(),'password':$('#d2').val()}; //获取input框数据
//JSON.stringify相当于json.dumps(),转化成json格式的字符串
var pos = JSON.stringify(pos_data); //转换格式
$.ajax({
url:'',
type:'post',
data:pos, //发送的数据
contentType:'application/json', //告诉后端你这次的数据是json格式 dataType:'json',
success:function (data) {
alert(data)
}
})
})
</script>
</html>
视图层
#ajax提交json数据 def home_json(request): if request.method == 'POST': #后端 需要手动去request.body中获取json格式数据 print(request.body) import json bytes_str = request.body.decode('utf-8') print(json.loads(bytes_str)) return HttpResponse('ok') return render(request,'home_json.html')
路由层
url(r'^home_json/',views.home_json,name='home_json'),
总结:
1.如果不是上传文件,form表单input的话,就直接传了,contentType默认是urlencoded编码方式 2.如果是上传文件,ajax上传文件就是先创建一个Formdata对象,通过append,把key,value参数传进去。注意:form表单和ajax上传的文件都是通过request.FILES.get()获取。 3.ajax提交json格式的数据,先创造出一个对象,把数据放在对象里面,然后转换成json格式的字符串,通过JSON.stringify(data),这里的contentType必须设置为'application/json',这样它的数据在视图中就能通过request.body获取到,是二进制格式,需要转换成字符串。 4、在前端接收到后台json格式数据,可以在ajax那里写dataType:'json',它会自动转换成对象
六、序列化组件(主要用于自定义分页器)
from django.core import serializers # django自带的一个小型的序列化工具 def reg(request): user_list = models.User.objects.all() res = serializers.serialize('json',user_list) return render(request,'index.html',locals())
[{ "model": "app01.user", "pk": 1, "fields": { "username": "jason", "age": 18, "gender": 1 } }, { "model": "app01.user", "pk": 2, "fields": { "username": "tank", "age": 24, "gender": 3 } }, { "model": "app01.user", "pk": 3, "fields": { "username": "egon", "age": 73, "gender": 2 } }, { "model": "app01.user", "pk": 7, "fields": { "username": "kevin", "age": 29, "gender": 4 } }]
七、内置分页器
1、为什么要用分页器?
1 项目数据量大了以后,比如涉及到分页,一页一页的加载显示
2 Django中分页器组件,把分页常用的东西,封装到一个类中
3 实例化得到一个对象,对象里有属性和方法
2、如何使用分页器
#1 Paginator对象的属性和方法 book_list=models.Book.objects.all() # 实例化得到对象 # 第一个参数:要分页的数据,book_list # 第二个参数:每页条数 paginator=Paginator(book_list,10) # Paginator对象的属性和方法 print(paginator.per_page) # 每页显示的条数 print(paginator.count) # 总条数,总共要分页多少条数据 print(paginator.num_pages) # 总页码数 print(paginator.page_range) # 页码的生成器 [1,2,3,4,5,6,7,8,9,10] #3 Page对象的属性和方法 # Page类 的对象 page=paginator.page(2) # 第一页的对象 # 每一页的对象,属性和方法 print(page.has_next()) # 有没有下一页 print(page.next_page_number()) # 下一页页码 print(page.has_previous()) # 是否有上一页 print(page.previous_page_number()) # 上一页页面 (当前页如果是第一页,没有上一页) print(page.object_list) # 当前页的所有数据 print(page.number) # 当前页的页码数 # 4 表模型中默认以id排序 class Meta: ordering=('id', ) # 默认以id排序
完整的分页器视图
from django.core.paginator import Paginator def index(request): # 需要的第三个参数 page_num_int = int(request.GET.get('page', 1)) #拿到url后的参数,当做页码数,实现翻页跳转 book_list = models.Book.objects.all() paginator = Paginator(book_list, 1) # 需要的第一个参数:页码的生成器 [1,2,3,4,5,6,7,8,9,10] # page_range = paginator.page_range if paginator.num_pages > 11: # 当前条件符合了以后,有三种情况 if page_num_int - 5 < 1: page_range = range(1, 11) elif page_num_int + 5 > paginator.num_pages: page_range = range(paginator.num_pages - 10, paginator.num_pages + 1) else: page_range = range(page_num_int - 5, page_num_int + 5) else: page_range = paginator.page_range # 需要的第二个参数,去到某一页的page对象 page = paginator.page(page_num_int) return render(request, 'index.html', {'page_range': page_range, 'page': page, 'page_num_int': page_num_int})
模板
<body> <div class="container-fluid"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <table class="table"> <thead> <tr> <th>id</th> <th>名字</th> <th>价格</th> </tr> </thead> <tbody> {% for book in page.object_list %} <tr> <td>{{ book.id }}</td> <td>{{ book.name }}</td> <td>{{ book.price }}</td> </tr> {% endfor %} </tbody> </table> <div class="text-center"> <nav aria-label="Page navigation"> <ul class="pagination"> {% if page.has_previous %} <li> <a href="/?page={{ page.previous_page_number }}" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% else %} <li class="disabled"> <a href="" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> {% endif %} {% for page_num in page_range %} {% if page_num_int == page_num %} <li class="active"><a href="/?page={{ page_num }}">{{ page_num }}</a></li> {% else %} <li><a href="/?page={{ page_num }}">{{ page_num }}</a></li> {% endif %} {% endfor %} {% if page.has_next %} <li> <a href="/?page={{ page.next_page_number }}" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> {% else %} <li class="disabled"> <a href="" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> {% endif %} </ul> </nav> </div> </div> </div> </div> </body>
八、模型表参数choice
比如选择性别男女,往数据库中填写的是数字1,2
模型层
class User(models.Model): username = models.CharField(max_length=32) age = models.IntegerField() choices = ( (1,'男'),(2,'女'),(3,'其他') ) gender = models.IntegerField(choices=choices)
视图层
user_obj = models.User.objects.filter(pk=1).first() print(user_obj.get_gender_display()) #男 """ 只要是choices字段 在获取数字对应的注释 固定语法 get_choices字段名_display() """
注意:
1 存choice里面罗列的数字与中文对应关系 print(user_obj.get_gender_display()) 只要是choices字段 通过数字获取对应的汉字
固定语法 get_choices字段名_display() 2 存没有罗列出来的数字 不会报错 还是展示数字