【2022-09-07】Django框架(七)
Django框架(七)
Django之Ajax
Ajax简介
- Asynchronous JavaScript + XML(异步JavaScript和XML), 其本身不是一种新技术,而是一个在 2005年被Jesse James Garrett提出的新术语,用来描述一种使用现有技术集合的‘新’方法,包括: HTML 或 XHTML, CSS, JavaScript, DOM, XML, XSLT, 以及最重要的 XMLHttpRequest。当使用结合了这些技术的AJAX模型以后, 网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载(刷新)整个页面。这使得程序能够更快地回应用户的操作。
- 尽管X在Ajax中代表XML, 但由于JSON的许多优势,比如更加轻量以及作为Javascript的一部分,目前JSON的使用比XML更加普遍。JSON和XML都被用于在Ajax模型中打包信息。
- 朝后端发送请求的方式:
1.浏览器地址栏直接数据url访问 >> GET请求
2.a标签href属性 >> GET请求
3.form表单 >> GET/POST请求(使用method属性来控制)
# Ajax
4.Ajax >> GET/POST请求
- Ajax的特点:
# 异步提交,局部刷新
# Ajax最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容(这一特点给用户的感受是在不知不觉中完成请求和响应过程)
- 使用须知:
Ajax现在市面上都使用的是jQuery封装之后的版本(原生的复杂并且在实际项目中也一般不用)
# 所以:在前端页面使用Ajax的时候需要确保导入了jQuery
px:并不只有jQuery能够实现Ajax,其他的框架也可以,但是都是一样的原理。
Ajax基本语法与使用
- 善意提醒:
# 记得导入jQuery模块
<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
- Ajax语法格式:
// 记得写在js中或者<script>标签中
// 创建ajax朝后端发送
$.ajax({
url:"", //请求地址:不写默认朝当前地址提交
type:"post", //请求方式:不写默认为get请求
data: formdata, //请求数据
contentType:false, //发送到服务器内容的编码类型
processData:false, //处理数据
// 回调函数:当后端有返回结果的时候自动触发,args来接收后端的返回结果
success:function(data){ //执行成功的操作
alert("")
console.log(data)
document.getElementById("p1").innerHTML=data.status;//包含标签innerHTML与value功能差不多
document.getElementById("fname").value=data.data.name;//不包含标签
document.getElementById("lname").value=data.data.age;
alert(data.list)
},
error:function(data){//执行失败的操作
alert("")
console.log(data)
}
- 示例:
# 需求:
页面上有三个input框
在前两个框中输入数字,点击按钮,朝后端发送ajax请求
后端计算出结果,在发返回给前端动态展示到第三个input框中
(整个过程页面不刷新,也不在前端计算)
- 前端:
<input type="text" id="d1"> +
<input type="text" id="d2"> =
<input type="text" id="d3">
<button id="b1">求和</button>
<script>
$('#b1').click(function (){ // 给b1绑定一个点击事件
// 朝后端发送ajax
$.ajax({
url:'', // 超当前地址提交
type:'post', // 指定请求方式
data:{'one':$('#d1').val(),'two':$('#d2').val()}, // 数据提交给后端(.val()方法获取用户输入在input框的数据)
// 回调函数:当后端给你返回结果的时候会自动触发 args接受后端的返回结果
success:function (args){
$('#d3').val(args)
}
})
})
</script>
- 后端:
# 后端:
def index(request):
if request.method == 'POST': # 判断post请求
one = request.POST.get('one') # 拿到ajax发送的数据(如果是列表则需要用到getlist)
two = request.POST.get('two')
out = int(one)+int(two) # 将两个数相加
return HttpResponse(out) # 返回给ajax的回调函数
return render(request,'index.html')
# 如果是跟ajax交互的话,后端无论返回什么都不会作用于浏览器,都会交给ajax的回调函数。
- 我们发现上述页面并没有刷新,但是实时动态的拿到了后端的数据。
- 研究JsonResponse返回给前端的数据类型:
def index(request):
if request.method == 'POST':
d = {'username':'jjj','age':123}
return HttpResponse(d)
return render(request,'index.html')
# 我们将字典的形式返回给前端页面,研究前端页面是否可以接收到。
# 前端页面只接受到了字典的键,所以HttpResponse是不能返回字典的形式的。
那么我们可以序列化之后在返回给前端,我们再来看一下:
import json
def index(request):
if request.method == 'POST':
d = {'username':'jjj','age':123}
return HttpResponse(json.dumps(d)) # 序列化字典
return render(request,'index.html')
我们可以看到传输到前端页面,并没有帮我们执行反序列化,那么这样就不能应用字典对象的方法。
# 这时我们就要用到我们的JsonResponse来帮我们实现
from django.http import JsonResponse
def index(request):
if request.method == 'POST':
d = {'username':'jjj','age':123}
return JsonResponse(d) # 使用JsonResponse模块序列化并返回到前端页面
return render(request,'index.html')
- 这样我们就可以在前端使用该对象的属性与方法。
Django前后端传输数据编码格式
- post请求编码格式:
# 我们主要来研究post请求前后端传输数据的编码格式
因为GET请求的编码格式显示在路由?后面的参数位置
eg:
username=gary&password=123
# 我们就可以看出来get请求的编码格式
- 前后端传输数据的编码格式有哪些:
# 常用的就是这三种:
urlencoded
formdata
json
- 朝后端发送post请求的方式有几种 :
# form表单 :method = 'POST'
# Ajax :type = 'post'
# 我们就来研究他们两个在传输数据的时候编码的不同而产生数据格式的不同。
# 研究他们到底是什么编码格式
- urls.py
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^index/',views.index)
]
- views.py
def index(request):
if request.method = 'POST':
print('request.POST')
print('request.FILES') # 要注意这里大打印操作,下述会用到他们的打印结果
return render(request,'index.html')
- html页面
<form action="" method="post"> # 指定请求方式
<p>username: <input type="text" name="username" class="form-control"> </p>
<p>password: <input type="password" name="password" class="form-control"></p>
<input type="submit" class="btn btn-success">
</form>
- 研究form表单
urlencoded:
# 在我们向后端提交post请求的时候我们可以看到,post请求的默认编码格式是urlencoded
那么urlencoded编码的数据格式,他的数据到底长什么样子呢?
# 数据格式:
username=gary&password=123&file=%E7%9F%A5%E8%AF%86%E7%82%B9.pdf
# 我们发现urlencoded编码的数据格式和GET请求的编码格式出来的数据格式几乎是一致的
# 后端接收到到的数据格式 :
<QueryDict: {'username': ['gary'], 'password': ['123'], 'file': ['知识点.pdf']}>
<MultiValueDict: {}>
form-data:
# 前端form表单添加属性:enctype="multipart/form-data"
<form action="" method="post" enctype="multipart/form-data">
# 后端接收到的数据:
<QueryDict: {'username': ['gary'], 'password': ['123']}>
<MultiValueDict: {'file': [<InMemoryUploadedFile: 知识点.pdf (application/pdf)>]}>
- 总结:
django后端针对符合urlencoded编码格式的数据都会自动帮我们解析封装到request.POST中
# 这要数据格式是这样子的:username=jason&password=123
都会解析到 >>> request.POST里面(包括文件数据)
如果你把编码格式改成formdata,那么针对普通的键值对还是解析到request.POST中,而将文件解析到request.FILES中
# form表单是无法发送json格式的数据的。只可以发送urlencoded和form-data
- 研究Ajax
<input type="button" class="btn btn-danger" value="按钮" id="d1">
</form>
<script>
$('#d1').click(function (){
$.ajax({
url:'',
type:'post',
data:{'username':'gary','age':19},
success:function(){
}
})
})
</script>
# 创建一个普通按钮,触发点击事件,超后端发送Ajax
- 结论:
# 我们可以看到ajax也使用的是urlencoded编码格式,并且后端也使用的是request.POST接收数据
# 数据格式:username=gary&age=19
# 所以更加证实了:
django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中
# 并且ajax也是支持发送json格式数据和文件格式数据的
Ajax发送json格式数据
- 指定编码格式:
# Ajax默认的为urlencoded编码格式
# 但是可以使用contentType指定编码格式。
<input type="button" class="btn btn-success" value="按钮" id="d1">
<script>
$('#d1').click(function (){
$.ajax({
url:'',
type:'post',
data:{'username':'gary','age':19},
contentType:'application/json', # 指定编码格式json,全称:application/json
success:function (){
}
})
})
</script>
- 遵循条件:
# 前后端在传输数据的时候一定要确保编码格式跟数据正真的格式是一致的。
data:JSON.stringify({'username':'gary','age':19}), # 前端序列化
# 上述我们验证过只有urlencoded编码格式的数据才会自动帮你解析封装到request.POST中
那么我们来看一下是否可以接收:
# 就更加验证了
django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中
# django针对json格式的数据 不会做任何的处理
- request对象方法补充:
# request.is_ajax()
# 判断当前请求是否是ajax请求 返回布尔值
# request.body
# 接收二进制类型的数据
# 因为接受的是二进制类型那么在针对json格式的字符串,需要我们手动的处理:
import json
def db_json(request):
if request.is_ajax():
res = request.body # 拿到二进制类型的json类型字符串
json_str = res.decode('utf-8') # 解码为字符串类型
json_dict = json.loads(json_str) # 反序列化为字典类型
print(json_dict)
return render(request,'db_json.html')
# 补充:
# json.loads() 能够自动先解码再反序列化
# 所以:无需使用decode解码也可以
json_dict = json.loads(res)
- 总结:
ajax发送json格式数据需要注意点:
1.contentType参数指定成:application/json
2.数据是真正的json格式数据 # 前端需要序列化为json格式数据(JSON.stringify)
3.django后端不会帮你处理json格式数据需要你自己去request.body获取并处理
Ajax发送文件数据
# ajax发送文件数据,需要借助于js内置方法
# 关键字: FormData
# 作用:可存储普通数据和文件数据,一并发送给后端
- html页面
<p>files<input type="file" name="username" class="form-control" id="d3"></p>
<button class="btn btn-info" id="d4">上传</button>
<script>
$('#d4').click(function (){
// 需要先利用FormData内置对象
let formDataObj = new FormData();
// 添加普通的键值对
formDataObj.append('username',$('#d1').val())
formDataObj.append('password',$('#d2').val())
// 添加文件对象
formDataObj.append('file',$('#d3')[0].files[0])
// 将对象基于ajax发送给后端
$.ajax({
url:'',
type:'post',
data:formDataObj, // 可直接将对象放在data后面
// ajax发送文件必须要指定的两个参数
contentType:false, // 不需要使用任何的编码,django后端能够自动识别fromdata对象
processData:false, // 告诉浏览器不要对数据进行任何的优化和处理
})
})
</script>
- 后端:
def db_files(request):
if request.is_ajax():
if request.method == 'POST':
print(request.POST)
print(request.FILES)
return render(request,'db_files.html')
- 总结:
# 1、需要利用内置对象FormData
let formDataObj = new FormData();
# 2、添加普通的键值对
formDataObj.append('username',$('#d1').val())
formDataObj.append('password',$('#d2').val())
# 3、添加文件对象
formDataObj.append('file',$('#d3')[0].files[0])
# 4、指定两个关键性的参数:
contentType:false, // 不需要使用任何的编码,django后端能够自动识别fromdata对象
processData:false, // 告诉浏览器不要对数据进行任何的优化和处理
# 5、结论:
django后端能够直接识别到formdata对象并且能够将内部的普通键值自动解析并封装到request.POST中 文件数据自动解析并封装到request.FILES中
回调函数
回调函数
后端跟ajax交互 不应该再返回页面 通常情况下都是返回json格式数据
前端针对HttpResponse和JsonResponse返回的json格式数据处理策略不同
前者不会自动反序列化 而后者会自动反序列化
如果想让前者也自动反序列化可以添加一个固定的参数
dataType:'JSON'
Django序列化组件serialize
# 前后端分离的项目
作为后端开发的我们只需要写代码将数据处理好
能够序列化返回给前端即可
再写一个接口文档 告诉前端每个字段代表的意思即可
前端对数据做处理也是比较麻烦的。
# 所以我们在写前后端分离项目的时候,要想让前端页面也能够识别到后端的数据,那就要用到json格式的数据来进行交互。
- models.py
class User(models.Model):
username = models.CharField(max_length=32)
age = models.IntegerField()
gender_choice = (
(1,'male'),
(2,'female'),
(3,'others')
)
gender = models.IntegerField(choices=gender_choice)
- 在讲解序列化组件之前我们先来看一个例子:
# 需求:在前端获取到后端用户表里面所有的数据 并且要是列表套字典的格式
# 我们先用我们基础阶段的知识来完成这个效果:
- html页面
<body>
{% for user_obj in user_list %}
<p>{{ user_obj }}</p>
{% endfor %}
</body>
- views.py
from django.http import JsonResponse # 导入JsonResponse模块
from app01 import models
def ab_ser(request):
user_queryset = models.User.objects.all() # 查询所有的数据对象
user_list = [] # 创建一个空列表
for user_obj in user_queryset: # 循环出每一个数据对象
tmp = { # 利用对象点的方式取出每一个对应元素来充当字段的值
'pk':user_obj.pk,
'username':user_obj.username,
'age':user_obj.age,
'gender':user_obj.gender
}
user_list.append(tmp) # 添加到列表中
return JsonResponse(user_list, safe=False) # 转换成json格式返回给前端页面(safe属性为ture则表示只能传dict字典的形式,因为现在为列表的形式,所以改为False)
# 这样就可以返回给前端我们需要的格式(列表套字典的格式)信息。
[
{"pk": 1, "username": "gary", "age": 19, "gender": 1},
{"pk": 2, "username": "tom", "age": 20, "gender": 2},
{"pk": 3, "username": "kevin", "age": 29, "gender": 3},
{"pk": 4, "username": "jack", "age": 38, "gender": 4}
]
# 这样写是不是非常的麻烦,如果字段非常的多 我们还要把所有的字段,字段对应的值拿出来,并且如果添加新的字段,我们还需要手动来操作添加新的键值对。
# 我们在写前后端分离的时候,有很多专门为我们做序列化组件的模块,我们这里来介绍一个:
- 序列化模块serialize
# 格式:serializers.serialize('序列化成什么格式',数据)
# 示例:
from django.core import serializers # 导入
def ab_ser(request):
user_queryset = models.User.objects.all()
res = serializers.serialize('json',user_queryset) # 序列化成json格式数据
"""会自动帮你将数据变成json格式的字符串 并且内部非常的全面"""
return HttpResponse(res) # 返回给前端页面
'''
[{"model": "app01.user",
"pk": 1,
"fields": {"username": "gary", "age": 19, "gender": 1}},
{"model": "app01.user",
"pk": 2,
"fields": {"username": "tom", "age": 20, "gender": 2}},
{"model": "app01.user",
"pk": 3,
"fields": {"username": "kevin", "age": 29, "gender": 3}},
{"model": "app01.user",
"pk": 4,
"fields": {"username": "jack", "age": 38, "gender": 4}}]
'''
# 我们可以看到它帮我们处理的数据是非常全面的,
# 告诉了我们这个数据来自于哪一个应用下的拿一张表,还告诉了我们对应的主键值,和详细信息
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律