Django ajax的简单使用、自定义分页器
一. ajax初识
1. 前后端传输数据编码格式contentType
使用form表单向后端提交数据时,必须将form表单的method由默认的get改为post,如果提交的数据中包含文件,还要将form表单的enctype由默认的"application/x-www-form-urlencoded"修改为"multipart/form-data"。
我们可以通过谷歌浏览器-》检查 中的Network查看网络请求的详细信息。
以form表单为例,其中代码如下(用Bootstrap装饰了一下):
输入用户名密码,然后随便选一个文件点提交:
点击view source查看原生数据:
随后发现后端能拿到文件,不过只是文件名而已:
随后修改将enctype修改为"multipart/form-data",然后再次提交该文件:
此时原生数据中file看不到了,不过后端可以看到request.FILES中收到了真实的文件,使用GET可以拿到对应的文件对象。
2. 小结
前后端传输数据编码格式contentType:
1. application/x-www-form-urlencoded
- 对应的数据格式:name=jason&password=666&myfile=test.py
- 后端获取数据:request.POST
2. multipart/form-data
- 对应的数据格式:name=jason&password=666
- 后端获取文件格式数据:request.FILES
- 后端获取普通键值对数据:request.POST
注意:django会将urlencoded编码的数据解析自动放到request.POST,即使修改了编码格式,只要有其中有普通的键值对,都能通过request.POST取到数据。
二. ajax的简单使用
前端朝后端发送请求的方式有四种:
- 浏览器窗口手动输入网址(get请求)
- a标签的href属性(get请求)
- form表单(get、post请求,默认是get请求)
- ajax(get、post请求)
前面三种我们都已经接触过了,接下来来看看第四种ajax。
- AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步的Javascript和XML”。即使用Javascript语言与服务器进行异步交互(客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。),传输的数据为XML(当然,传输的数据不只是XML)。
- AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
- AJAX 最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容。(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
- AJAX 不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。
2.1 ajax的基本语法
ajax主要由四个部分组成:
$('#d1').click(function () { $.ajax({ // 提交的地址,不写默认提交至当前页面,同form表单的action url:'/index/', // 提交的方式 type:'post', // 提交的数据,一般以键值对的形式出现 data:{'name':'jason','password':'123'}, // 回调函数 success:function (data) { // data接收的就是异步提交返回的结果 alert(data) } }) })
注意:ajax传输数据的默认编码格式也是urlencoded。前后端传输数据时,数据格式与编码要一一对应,比如传输文件就要将编码改为formdata。
2.2 ajax实现前端数字相加
假设有三个input框,需求是前两个input框输入数字,点击提交按钮后将结果显示在第三个input中,中途页面不刷新且加法运算要通过后端实现。
大致思路如下:
- 拿到input框中输入的数字
- 将数字传至后端进行运算
- 后端将运算的结果返回给前端
- 前端将结果展示在第三个input框中
首先假设用户输入的均为数字,所以我们不做任何检验。然后ajax是异步JavaScript和XML,JQuery内部封装了JavaScript,我们这里使用JQuery的语法来获取input框中输入内容(JQuery_obj.val()),然后使用ajax的回调函数seccess来将加法运算的结果显示在第三个input框中(JQuery_obj.val(result))。
代码如下(前端未做任何装饰,可能有点丑):
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test1</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <input type="text" id="s1">+<input type="text" id="s2">=<input type="text" id="s3"> <button id="b1">提交</button> <script> $('#b1').on('click', function () { $.ajax({ url: '/test1/', //不写默认提交至当前页面 type: 'post', data:{'s1':$('#s1').val(),'s2':$('#s2').val()}, success:function (data) { $('#s3').val(data) } }) }) </script> </body> </html>
def test1(request): if request.method == 'POST': print(request.POST) s1 = request.POST.get('s1') s2 = request.POST.get('s2') # 拿到的前端数据均为字符串格式,所以需要类型转换 res = int(s1) + int(s2) return HttpResponse(res) return render(request, 'test1.html')
2.2 ajax传输JSON数据
各编程语言与前端数据传输通常使用json格式,因为json支持多种语言,各编程语言都有相应的json语法。在python中是使用json.dumps()和json.loads()分别实现对象的序列化和反序列化。而JavaScript中是使用JSON.stringify()和JSON.parse()分别实现对象的序列化和反序列化。
向后端传输JSON数据时,需要修改编码类型,不然会出现以下情况:
以上情况的出现是因为编码与数据格式不匹配造成的,你传输的是JSON格式字符串,而编码urlencode却让后端拿到的是字典,所以就直接把你的JSON字符串当初字典的key,value拿个空来自己造一个字典出来了。
为了统一编码和数据格式,需要将编码设置为‘application/json’。
代码如下:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test1</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> </head> <body> <button id="b1">提交</button> <script> $('#b1').on('click', function () { $.ajax({ url:'', type:'post', data:JSON.stringify({'name': 'json', 'password': '123'}), contentType:'application/json', success:function (data) { alert(data) } }) }) </script> </body> </html>
def test1(request): if request.method == 'POST': import json # 编码改成application/json之后,传输过来的是二进制数据,存在request.body中 dic = json.loads(request.body.decode('utf-8')) print(dic, type(dic)) return HttpResponse('get it') return render(request, 'test1.html')
2.3 ajax传输文件
传输文件相比传输json字符串要复杂一些,首先要想办法把用户上传的文件取出来,这需要用到JavaScript中的FormData对象的方法,其次还是要统一数据格式与编码,将编码改为false(因为formdata内部有自带一个编码)。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>test1</title> <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script> <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script> <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet"> </head> <body> file:<input type="file" name="myfile" id="f1"> <button id="b1">提交</button> <script> $('#b1').on('click', function () { let formdata = new FormData();//生成一个FormData对象 //$('#f1')[0]得到的是JQuery对象中的第一个JS对象,JS_obj.files拿到所有的文件,通过索引取第一个文件 formdata.append('file', $('#f1')[0].files[0]); $.ajax({ url:'', type:'post', contentType:false,//用FormData自带的编码,所以不需要设置contentType processData:false,//告诉浏览器不要处理数据 data: formdata,//直接将formdata提交至后端即可 success:function (data) { alert(data) } }) }) </script> </body> </html>
def test1(request): if request.method == 'POST': # 没有普通键值对,所以request.POST是空 print(request.POST) print(request.FILES) # request.FIlES.get('file')拿出来的是文件对象 file_obj = request.FILES.get('file') # 保存文件至本地 with open(file_obj.name, 'wb') as f: for line in file_obj: f.write(line) return HttpResponse('get it') return render(request, 'test1.html')
三. 批量插入,分页器的简单实现
先在数据库中创建多条数据,然后展示在页面上,这里以1000条为例。
def test1(request): for i in range(100): models.Book2.objects.create(name='第%s本' % i) book_list = models.Book2.objects.all() return render(request, 'test1.html', locals())
以上这么增加数据时,发现要在页面等一段时间才会有数据显示,因为写入数据库要时间,前端只能等待数据写入数据库结束。这种情况需要用到批量插入bulk_create:
def test1(request): # 定义一个列表 book_list = [] for i in range(100): # 实例化出Book2的对象,并将其加入列表 book_list.append(models.Book2(name='第%s本' % i)) # 这就是批量导入的精髓,相当于异步,程序执行无需等待该代码执行完毕,可直接去执行后续代码 models.Book2.objects.bulk_create(book_list) # 随后前端直接可以使用book_list中的书籍对象点属性去展示内容,不需要等数据库中数据写入完毕 return render(request, 'test1.html', locals())
分页器是需要考虑一共有几页的,这需要依据数据总条数来定,其次分页器每一次只显示几个按钮,这就意味着我们是没法在前端来完成这个动态的过程的,只能在后端完成,这时候需要用到后端或者前端的取消转义语法。
html = '' for i in range(1,pager_nums+1): html += '<li><a href="?page=%s">%s</a></li>'%(i,i)
最终代码如下:
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)
先在应用下新建一个叫utils的文件夹,里面创建一个.py文件,将该代码拷贝进去保存。然后将该py文件导入到views.py中。
from django.shortcuts import render,HttpResponse from app01 import models # 导入拷贝了上述分页器代码的py文件 from app01.utils import my_page def booklist(request): book_list = models.Book2.objects.all() # 拿到数据总条数 all_count = book_list.count() # 得到当前页面,前端的分页器被点击时返回page,标明用户点击的页编号 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] return render(request,'booklist.html',locals())
原文地址:https://www.cnblogs.com/maoruqiang/p/11025979.html
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法