Django之Ajax
什么是Ajax?
- ajax 全名: async javascript and XML(异步JavaScript和XML)
- 是前后台交互的能⼒, 也就是我们客户端给服务端发送消息的⼯具,以及接受响应的⼯具
- AJAX 不是新的编程语言,而是一种使用现有标准的新方法。
- AJAX 是与服务器交换数据并更新部分网页的艺术,在不重新加载整个页面的情况下。
- 是⼀个默认异步执⾏机制的功能,AJAX分为同步(async = false)和异步(async = true)
什么是同步请求?(false)
1 同步请求是指当前发出请求后,浏览器什么都不能做, 2 必须得等到请求完成返回数据之后,才会执行后续的代码, 3 相当于生活中的排队,必须等待前一个人完成自己的事物,后一个人才能接着办。 4 也就是说,当JS代码加载到当前AJAX的时候会把页面里所有的代码停止加载,页面处于一个假死状态, 5 当这个AJAX执行完毕后才会继续运行其他代码页面解除假死状态
什么是异步请求?(默认:true)
1 默认异步:异步请求就当发出请求的同时,浏览器可以继续做任何事, 2 Ajax发送请求并不会影响页面的加载与用户的操作,相当于是在两条线上,各走各的,互不影响。 3 一般默认值为true,异步。异步请求可以完全不影响用户的体验效果, 4 无论请求的时间长或者短,用户都在专心的操作页面的其他内容,并不会有等待的感觉。
Ajax 的优势
- AJAX使用JavaScript技术向服务器发送异步请求;
- AJAX请求无须刷新整个页面;
- 因为服务器响应内容不再是整个页面,而是页面中的部分内容,所以AJAX性能高;
- 两个关键点:1.局部刷新,2.异步请求
应用场景
搜索引擎根据用户输入的关键字,自动提示检索关键字。
还有一个很重要的应用场景就是注册时候的用户名的查重。
其实这里就使用了AJAX技术!当文件框发生了输入变化时,使用AJAX技术向服务器发送一个请求,然后服务器会把查询到的结果响应给浏览器,最后再把后端返回的结果展示出来。
- 整个过程中页面没有刷新,只是刷新页面中的局部位置而已!
- 当请求发出后,浏览器还可以进行其他操作,无需等待服务器的响应!
当输入用户名后,把光标移动到其他表单项上时,浏览器会使用Ajax技术向服务器发出请求,服务器会查询名为lemontree7777777的用户是否存在,最终服务器返回true表示名为lemontree7777777的用户已经存在了,浏览器在得到结果后显示“用户名已被注册!”。
- 整个过程中页面没有刷新,只是局部刷新了;
- 在请求发出后,浏览器不用等待服务器响应结果就可以进行其他操作;
Ajax 的操作流程
具体操作流程:
- 首先通过PHP页面将数据库中的数据取出
- 取出后转成json格式的字符串,后利用ajax把字符串返还给前台
- 再利用json.parse解析通过循环添加到页面上
- 那么反之,前端的数据可以利用ajax提交到后台
- 但是后台是没有办法直接把这些数据插入到数据库中,所以要先提交到PHP页面上
- 最后再由PHP将数据插入到数据库中
基本语法
$('#subBtn').click(function (){ //发送ajax请求 $.ajax({ url:'', //后端地址,三种填写方式,与form标签的action一致 type:'post', //请求方式,默认也是get data:{'v1':$('#d1').val(),'v2':$('#d2').val()}, //获取两个框里面的数据 success:function (args){ //后端返回结果之后自动触发,args接收后端返回的数据 $('#d3').val(args) } }) })
示例:
# 路由层 urls.py 文件
from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('ab_ajax/',views.ab_ajax_func)
# 视图层 views.py 文件
from django.shortcuts import render, HttpResponse def ab_ajax_func(request): if request.method == 'POST': print(request.POST) v1 = request.POST.get('v1') v2 = request.POST.get('v2') res = int(v1) + int(v2) return HttpResponse(res) return render(request, 'abAjaxPage.html')
# 模板层 abAjaxPage.html 文件
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script> </head> <body> <input type="text" id="d1"> + <input type="text" id="d2"> = <input type="text" id="d3"> <button id="subBtn">计算</button> <script> //给按键绑定点击事件 $('#subBtn').click(function (){ //发送ajax请求 $.ajax({ url:'', //后端地址,三种填写方式,与form标签的action一致 type:'post', //请求方式,默认也是get data:{'v1':$('#d1').val(),'v2':$('#d2').val()}, //获取两个框里面的数据 success:function (args){ //后端返回结果之后自动触发,args接收后端返回的数据 $('#d3').val(args) } }) }) </script> </body> </html>
前后端数据传输的编码格式
1.前端可以向后端发起post请求的方式
- form 表单
- ajax 请求
2.基于post请求, 前后端数据传输的主流编码格式有三种
- urlencoded : 默认的编码格式, 提交的数据从request.POST中提取
- form-data : 上传文件时使用的编码格式, 提交的数据从request.POST中提取, 上传的文件从request.FILES中提取
- json : ajax发送的json格式数据, 在request.POST中取不到数据, 需要在request.body中提取数据
3.基于post请求, form表单传输数据默认的编码格式
- 默认编码格式为 : urlencoded
- 如果要上传文件需要在标签中指定 : enctype="multipart/form-data" 编码格式
- 数据格式 : username=alex&password=123
- 提交位置 : django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中, 文件提交到request.FILES中
4.基于post请求, ajax传输数据默认编码格式
- 默认编码格式 : urlencoded
- 如果要上传文件需要使用 Formdata 对象
- 数据格式 : username=alex&password=123
- 提交位置 : django后端会自动帮你解析封装到request.POST中, 文件提交到request.FILES中
5.json.loads( )是否可以转Bytes格式
- 3.5之前不行, 需要我们手动将 Bytes 格式转成 str 类型, 然后再进行转换
- 3.6以后可以, Bytes无需手动转 str 类型, 它内部会自动帮你转成 str, 再转成 json
- 查看 json.loads( ) 的源码可以得到验证 :
Ajax发送数据
Ajax发送json格式数据
# 模板层:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script> </head> <body> <button id="d1">发送json格式数据</button> <script> $('#d1').click(function (){ $.ajax({ url:'', type:'post', data:JSON.stringify({'name':'alex','age':18}), # 告诉后端发送的是json格式数据 contentType:'application/json', //指定字符编码格式 success:function (args){ alert(args) } }) }) </script> </body> </html>
后端拿到二进制格式的JSON格式字符串。Django针对json格式数据后端需要手动处理。
后端如何处理json格式字符串
# 视图层:
from django.shortcuts import render def ab_ajax_func(request): if request.method == 'POST': print(request.POST) # <QueryDict: {}> print(request.FILES) # <MultiValueDict: {}> print(request.body) # b'{"name":"alex","age":18}' import json res = json.loads(request.body) # json.loads()自带解码功能 print(res,type(res)) # {'name': 'alex', 'age': 18} <class 'dict'> request.JSON =res # 也可以将处理好的数据自己进行封装 print(request.JSON) # {'name': 'alex', 'age': 18} return render(request, 'abAjaxPage.html')
- contentType 参数 指定成 : application/json
- 数据必须是真正的json格式数据
- Django后端不会处理json格式数据,需要到request.body获取并处理
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>
</head>
<body>
<input type="file" id="d2">
<button id="d3">发送文件数据</button>
<script>
$('#d3').click(function (){
//1.先产生一个FormData对象
let myFormDataObj = new FormData();
//2.往该对象中添加普通数据
myFormDataObj.append('name','alex');
myFormDataObj.append('age',18);
//3.往该对象中添加文件数据,$('#d2')取索引0,转为原生jQuery对象即原生标签对象,再用files[0]就获得用户传的文件对象
myFormDataObj.append('file',$('#d2')[0].files[0])
//4.发送ajax请求
$.ajax({
url:'',
type:'post',
data:myFormDataObj,
//ajax发送文件数据固定的两个配制
contentType:false, //告诉浏览器不需要带任何编码,Django后端能够自动识别formdata对象,
processData: false, //告诉浏览器,不要对数据进行任何处理,原封不动发送到后端。
success:function (args){
alert(args) } }) }) </script> </body> </html>
# 视图层:
from django.shortcuts import render def ab_ajax_func(request): if request.method == 'POST': print(request.POST) # QueryDict: {'name': ['alex'], 'age': ['18']}> print(request.FILES) # <MultiValueDict: {'file': [<InMemoryUploadedFile: 试卷.pdf (application/pdf)>]}> return render(request, 'abAjaxPage.html')
Ajax发送文件需要注意的点:
- 需要利用内置对象FormData,普通键值对和文件都能发送
obj.append('name','alex'); obj.append('password',$('#pwd').val()); obj.append('file',$('#d2')[0].files[0])
- 需要指定两个关键性的参数
1 contentType: false 2 processData: false
-
Django后端能够直接识别formdata对象,并且能够将内部的普通键值对自动解析并封装到你request.POST中,文件数据对象自动解析并封装到reuqest.FILES中
Ajax补充说明
1. 后端request.is_ajax()
用于判断当前请求是否由ajax发出
2. 后端返回的三板斧都会被args接收,不再影响整个浏览器页面
3. 选择使用ajax做前后端交互的时候,后端一般返回的都是字典数据
字典数据前后端交互的几种方式
1. 直接发送
# 视图层:
from django.shortcuts import render, HttpResponse def ab_ajax_func(request): if request.method == 'POST': user_dict = {'username': 'alex', 'hobby': 'reading'} return HttpResponse(request, user_dict) # 将字典直接的发送给前端 return render(request, 'AjaxPage.html')
# 模板层:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script> </head> <body> <button id="d1">发送ajax请求</button> <script> $('#d1').click(function (){ $.ajax({ url:'', type:'post', data:{'name':'alex'}, success:function (args){ console.log(args); console.log(typeof args) } }) })
2. 后端先转成json格式,再发送给前端
# 视图层:
from django.shortcuts import render, HttpResponse def ab_ajax_func(request): if request.method == 'POST': user_dict = {'username': 'alex', 'hobby': 'reading'} import json user_data = json.dumps(user_dict) # 将字典转成jaon格式 return HttpResponse(user_data) return render(request, 'AjaxPage.html')
# 模板层:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script> </head> <body> <button id="d1">发送ajax请求</button> <script> $('#d1').click(function (){ $.ajax({ url:'', type:'post', data:{'name':'alex'}, success:function (args){ console.log(args) console.log(typeof args) } }) })
结果:
上述处理结果发现,返回的是json格式的字符串类型,在前端还是没有办法通过点的方式来取值,所以还需要在前端加上一步操作:
3. JOSN.parse()反序列化
# 视图层:
from django.shortcuts import render, HttpResponse def ab_ajax_func(request): if request.method == 'POST': user_dict = {'username': 'alex', 'hobby': 'reading'} import json user_data = json.dumps(user_dict) # 将字典转成jaon格式 return HttpResponse(user_data) return render(request, 'AjaxPage.html')
# 模板层:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script> </head> <body> <button id="d1">发送ajax请求</button> <script> $('#d1').click(function (){ $.ajax({ url:'', type:'post', data:{'name':'alex'}, success:function (args){ let userObj = JSON.parse(args); console.log(userObj); console.log(typeof userObj) console.log(userObj.username) } }) }) </script> </body> </html>
4. dataType:'json'
ajax自动反序列化后端的json格式的bytes类型数据
# 视图层:
from django.shortcuts import render, HttpResponse def ab_ajax_func(request): if request.method == 'POST': user_dict = {'username': 'alex', 'hobby': 'reading'} import json user_data = json.dumps(user_dict) # 将字典转成jaon格式 return HttpResponse(user_data) return render(request, 'AjaxPage.html')
# 模板层:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script> </head> <body> <button id="d1">发送ajax请求</button> <script> $('#d1').click(function (){ $.ajax({ url:'', type:'post', data:{'name':'alex'}, dataType:'json', {# 告诉前端发送过来的为json格式字符串 #} success:function (args){ console.log(args); console.log(typeof args) console.log(args.username) } }) }) </script> </body> </html>
结果:
但是3、4两种操作在前后端都需要进行处理,太过麻烦,有没有简单一点的方法呢?
5. 后端通过JsonResponse处理
# 视图层:
from django.shortcuts import render, HttpResponse def ab_ajax_func(request): if request.method == 'POST': user_dict = {'username': 'alex', 'hobby': 'reading'} from django.http import JsonResponse return JsonResponse(user_dict) return render(request, 'AjaxPage.html')
# 模板层:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script> </head> <body> <button id="d1">发送ajax请求</button> <script> $('#d1').click(function (){ $.ajax({ url:'', type:'post', data:{'name':'alex'}, success:function (args){ console.log(args); console.log(typeof args) console.log(args.username) } }) }) </script> </body> </html>
结果: