Ajax
目录
Ajax知识准备Json
什么是Json
JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
JSON 是轻量级的文本数据交换格式
stringify与parse方法
JavaScript中关于JSON对象和字符串转换的两个方法:
JSON.parse(): 用于将一个 JSON 字符串转换为 JavaScript 对象
JSON.parse('{"name":"Howker"}'); JSON.parse('{name:"Stack"}') ; // 错误 JSON.parse('[18,undefined]') ; // 错误JSON.stringify(): 用于将 JavaScript 值转换为 JSON 字符串
JSON.stringify({"name":"Tonny"})
Ajax简介
Ajax,全称为Asynchronous JavaScript and XML,即异步的JavaScript和XML。
它不是一门编程语言,
而是利用JavaScript在保证页面不被刷新、页面链接不改变 的 情况下与服务器交换数据 并更新部分网页的技术
同步交互:客户端发出一个请求后,需要等待服务器响应结束后,才能发出第二个请求;阻塞
Ajax异步交互:客户端发出一个请求后,无需等待服务器响应结束,就可以发出第二个请求。非阻塞,通过异步回调机制 callback()返回结果
与后端进行交互的方式:
浏览器地址栏输入url: GET
a标签href:GET/POST
form表单:GET/POST
Ajax: GET/POST
初始Ajax
案例:页面有三个input框,一个按钮
用户在前两个框中输入数字,点击按钮保证页面不刷新的情况下将数据发到后端做计算
将计算好的结果再发给前端展示到第三个input框中,基于jQuery封装的Ajax
index.html
<input type="text" id="i1"> + <input type="text" id="i2"> = <input type="text" id="i3"> <button id="d1">按钮</button> <script> $('#d1').click(function () { // 获取两个框里的内容,向后端提交异步请求 // ajax基本语法 $.ajax({ // 1 向哪个后盾提交数据 url: '', // 2 指定提交当前请求的方式 type: 'post', // 3 提交的数据 data: {'i1':$('#i1').val(), 'i2':$('#i2').val()}, // 4 ajax是异步提交,所以需要给一个回调函数来处理返回结果 success: function (data) { // data就是异步提交的返回结果 // 将异步回调的结果通过DOM操作渲染到第三个input框中 $('#i3').val(data) } }) }) </script>views.py
def index(request): if request.method == 'POST': i1 = request.POST.get('i1') i2 = request.POST.get('i2') i3 = int(i1) + int(i2) return HttpResponse(i3) return render(request,'index.html')urls.py
from django.conf.urls import url from app01 import views urlpatterns = [ url(r'^index/', views.index) ]
Ajax常见应用常见
搜索引擎根据用户输入关键字,自动提示检索关键字
还有一个很重要的应用场景就是注册时候的用户名的查重
其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来
整个过程中页面没有刷新,只是局部刷新了;
在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作
Ajax优缺点
- AJAX使用JavaScript技术向服务器发送异步请求;
- AJAX请求无须刷新整个页面;
- 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;
- 两个关键点:1.局部刷新,2.异步请求
$.ajax()方法参数
url:
要求为String类型的参数,(默认为当前页地址)发送请求的地址。
type:
要求为String类型的参数,请求方式(post或get)默认为get。注意其他http请求方法,例如put和delete也可以使用,但仅部分浏览器支持。
data:
要求为Object或String类型的参数,发送到服务器的数据。如果已经不是字符串,将自动转换为字符串格式。get请求中将附加在url后。防止这种自动转换,可以查看
processData
选项。对象必须为key/value格式,例如{foo1:"bar1",foo2:"bar2"}转换为&foo1=bar1&foo2=bar2。
如果是数组,JQuery将自动为不同值对应同一个名称。例如{foo:["bar1","bar2"]}转换为&foo=bar1&foo=bar2。
success:
要求为Function类型的参数,请求成功后调用的回调函数
由服务器返回,并根据dataType参数进行处理后的数据。
success:function (data){ //data可能是xmlDoc、jsonObj、html、text等等 }
Content-Type
content-type前后端传输数据的编码格式
urlencoded
formdata
application/json
form表单
默认是urlencoded编码格式传输数据
urlencoded数据格式
username=santa&password=123
django后端针对该格式的数据,会自动解析并帮你打包到request.POST中
formdata数据格式
- django后端针对符合urlencoded编码格式数据(普通键值对)还是统一解析到request.POST中
- 而针对formdata文件数据就会自动解析放到request.FILES中
ajax提交
ajax默认的也是urlencoded编码格式
前后端数据交互 编码格式与数据格式一定要一致
application/json
- django后端针对json格式数据 并不会做任何的处理,而是直接放在request.body中
Ajax发送数据
基于Ajax发送json数据
1 指定编码格式为application/json
2 将数据序列化为json串,保证与编码格式一致(前端的序列化JSON)
3 后端处理json格式的数据,不会做任何处理,原封不动的封装到request.body中
<button id="d3">ajax发送文件数据</button> <script> $('#d3').click(function () { $.ajax({ url: '', type: 'post', // 修改content-type 参数 contentType: 'application/json', data: JSON.stringify({'username': 'santa', 'password': '123'}), // 将数据序列化成json格式字符串 success: function (data) { alert(data) } }) }) </script>views.py
import json def ab_ct(request): if request.method == 'POST': print(request.body) # b'{"username":"santa","password":"123"}' json_bytes = request.body # json_str = json_bytes.decode('utf-8') # json_dict = json.loads(json_str) # print(json_dict) # {'username': 'santa', 'password': '123'} # 扩展 json.loads能够自动解码并序列化 json_dict = json.loads(json_bytes) print(json_dict) # {'username': 'santa', 'password': '123'} return render(request, 'ab_ct.html')
基于Ajax发送文件数据
1 借助于内置对象new FormData()
2 该对象可以携带文件数据,也可以传键值对
3 在Ajax中指定两个参数:
contentType:false 代表不使用任何编码格式,
processData:false 代表不对数据本身做任何处理,FormData()实例化的对象内部自带编码,django后端能够识别
<input type="file" name="myfile" id="i1"> <button id="d3">ajax发送文件数据</button> <script> $('#d3').click(function () { // 1 需要先生成一个内置对象 var myFormData = new FormData(); // 2 传普通键值对,当普通键值对较多的时候,我们可以利用for循环来添加 myFormData.append('username', 'santa'); myFormData.append('password', 123); // 3 传文件 myFormData.append('myfile', $('#i1')[0].files[0]); // 发送Ajax请求 $.ajax({ url: '', type: 'post', data: myFormData, // 发送formdata对象需要指定两个关键性的参数 processData:false, // 让浏览器不要对你的数据进行任何的操作 contentType:false, // 不要使用任何编码格式 对象formdata自带编码格式并且django能够识别该对象 success: function (data) { alert(data) } }) }) </script>views.py
def ab_ct(request): if request.method == 'POST': print(request.FILES) # <MultiValueDict: {'myfile': [<InMemoryUploadedFile: DJANGO点击.png (image/png)>]}> return render(request, 'ab_ct.html')
Django内置序列化功能(了解)
序列化目的:
将数据整合成一个大字典形式,再传给前端,方便数据的交互
一般用于前后端分离开发
drf django restframework from app01 import models from django.core import serializers # 以视图函数index为例 def ab_se(request): user_queryset = models.Userinfo.objects.all() # user_list = [] # for user_obj in user_queryset: # user_list.append({ # 'username':user_obj.username, # 'password':user_obj.password, # 'gender':user_obj.get_gender_display(), # }) # res = json.dumps(user_list) res = serializers.serialize('json',user_queryset) # return render(request,'ab_se.html',locals()) return HttpResponse(res) # res是一个字典套字典{{},{},{},{}...} # 每一个数据表中的记录作为一个字典 # 前端接收到的只有所有的字典,没有最外层的字典
批量插入数据
bulk_create
def ab_bc(request): # 先插入1000条件数据 # for i in range(1,1001): # models.Book.objects.create(title='第%s本书'%i) book_list = [] for i in range(1,10001): book_list.append(models.Book(title='新的%s书'%i)) models.Book.objects.bulk_create(book_list) # 批量插入数据的方式 book_queryset = models.Book.objects.all() return render(request,'ab_bc.html',locals())
自定义分页器
分页数据是通过总数据切片而来,queryset对象支持正数索引和正向步长,不支持负数
html
{% for book_obj in page_queryset %} <p>{{ book_obj.title }}</p> {% endfor %} {{ page_obj.page_html|safe }}views.py
from app01 import models from app01.utils.mypage import Pagination def ab_bc(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,pager_count=9) # 2 针对真实的queryset数据进行切片操作 page_queryset = book_queryset[page_obj.start:page_obj.end] return render(request,'ab_bc.html',locals())mypage.py
class Pagination(object): def __init__(self, current_page, all_count, per_page_num=10, 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)
Ajax结合sweetalert实现删除二次确认
<script> $('.cancel').click(function () { var $aEle = $(this); swal({ title: "你确定要删除吗?", text: "删除后数据将无法找回!", type: "warning", showCancelButton: true, confirmButtonClass: "btn-danger", confirmButtonText: "是的,我要删除", cancelButtonText: "算了吧,不删了", closeOnConfirm: false, closeOnCancel: false, showLoaderOnConfirm: true }, function(isConfirm) { if (isConfirm) { $.ajax({ url: '', type: 'post', data: {'delete_id': $aEle.attr("book_obj.pk")}, success: function (data) { if (data.code == 1000) { swal("success"); {#window.location.reload();#} $aEle.parent().parent().remove() } else { swal("error"); } } }); }else { swal ("取消删除") } }); }) </script>
代码中的注意点:
1、给可删除的标签添加类delete,绑定事件click
2、下面是编写事件程序的注意点:
通过
$(this)
得到当前标签3、要回传当前数据的id给服务器,通过设置标签自定义属性
deleteId={{obj.id}}
4、通过
$(this).attr(‘deleteId‘)
获取要删除的数据id5、通过DOM操作,实现局部的数据交互更新,但整个页面并不刷新
views.py
from django.http import JsonResponse import time def show_user(request): """ 前后端如果是通过ajax进行交互 那么交互的媒介一般情况下都是一个字典 :param request: :return: """ if request.method == 'POST': time.sleep(3) back_dic = {"code":1000,'msg':''} delete_id = request.POST.get('delete_id') models.Userinfo.objects.filter(pk=delete_id).delete() back_dic['msg'] = '删除成功,准备跑路!!!' return JsonResponse(back_dic) user_queryset = models.Userinfo.objects.all() return render(request,'show_user.html',locals())
django中如何开启事务
Django文件传输
相关推荐
结束数据方法的参数,该如何定义?-- 集合为自定义实体类中的结合属性,有几个实体类,改变下标就行了。<input id="add" type="button" value="新增visitor&quo