一、前后端传输数据的编码格式(contentType)
此内容主要是研究post请求数据的编码格式,因为get请求数据就是直接放在url后面的。
首先我们在前面叙述过可以朝后端发送post请求的方式有
- form表单
- Ajax
然后现在又了解到前后端传输数据的编码格式有
- urlencoded
- formdata
- json
1、研究form表单
(1)前端格式展示
<form action="" method="post" enctype="text/plain"></form>
<form action="" method="post" enctype="application/x-www-form-urlencoded"></form>
<form action="" method="post" enctype="multipart/form-data"></form>
(2)编码格式
form表单默认的编码格式是urlencoded,通过查看请求头中的 Content-Type 参数可以看出。
携带的数据格式:
username=xiao&password=123
django对urlencoded的处理:
django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中
django后端获取数据的模样:
<QueryDict: {'username': ['xiao'], 'password': ['123'], 'file': ['1755041963.jpg']}>
注意:
- 只要数据格式都是username=&password=&file=xxx.png ==> request.POST
- 如果你把编码格式改成formdata,那么针对普通的键值对还是解析到request.POST中,而文件将解析到request.FILES中。
- form表单是没办法发送json格式数据的
2、研究Ajax
Ajax默认的数据编码格式是urlencoded,通过查看请求头中的 Content-Type 参数可以看出。
携带的数据格式:
username=xiao&password=123
django对urlencoded的处理:
django后端针对符合urlencoded编码格式的数据都会自动帮你解析封装到request.POST中
django后端获取数据的模样:
<QueryDict: {'username': ['xiao'], 'password': ['123'], 'file': ['1755041963.jpg']}>
注意:
只要数据格式都是username=&password=&file=xxx.png ==>request.POST
3、示例
(1)后端
def index(request):
if request.method == 'POST':
print(request.POST)
# <QueryDict: {'username': ['dream'], 'password': ['1314521']}>
print(request.FILES)
# <MultiValueDict: {'img_file': [<InMemoryUploadedFile: 作用域链.drawio.png (image/png)>]}>
return render(request, 'index.html')
(2)前端
<form action="" method="post" enctype="multipart/form-data">
<p>username: <input type="text" name="username" class="form-control"></p>
<p>password: <input type="password" name="password" class="form-control"></p>
<p>file: <input type="file"></p>
<p><input type="submit" class="btn btn-success"></p>
<p><input type="button" class="btn btn-danger" value="按钮" id="d1"></p>
</form>
<script>
$("#d1").click(function () {
$.ajax({
url: '',
type: 'POST',
data: {"username": "dream", "password": 1314521},
success: function (args) {
},
})
})
</script>
ps:补充QueryDict
a. 本质上继承了原生的dict b. 字典能干的他都可以,字典不能干的,他基本上都不行 c. 就把他当成普通字典使用即可,中括号取值/赋值,get取值
二、ajax发送json格式数据
大前提:前后端传输数据的时候一定要确保编码格式跟数据真正的格式是一致的
(1)前端
在前端,将数据封装为json格式JSON.stringify(数据)
,并指定编码格式contentType: 'application/json'
。
<button class="btn btn-danger" id="d1">点我</button>
<script>
$('#d1').click(function () {
$.ajax({
url: '',
type: 'post',
// 前端数据转JSON格式数据 :JSON.stringify
data: JSON.stringify({"username": "dream", "password": 521521}),
// 不指定参数,默认就是 urlencoded
contentType: 'application/json',
success: function (args) {
}
})
})
</script>
发送的数据格式为:{“username”:“xiao”,“age”:18}
request.POST不会接收json格式的数据,django后端也不会对json格式的数据做进一步处理。
request.body可以用于接收json格式的数据,直接得到的是二进制格式的数据,需要在后端手动处理(解码+反序列化)。
(2)后端
def ab_json(request):
if request.is_ajax():
# 针对json格式数据需要你自己手动处理
json_bytes = request.body
# (1)方式一:先解码 再转换数据格式
json_str = json_bytes.decode('utf8')
json_dict = json.loads(json_str)
print(json_dict, type(json_dict)) # {'username': 'xiao', 'age': 18} <class 'dict'>
# (2)方式二:json.loads括号内如果传入了一个二进制格式的数据,那么内部会自动解码再反序列化
json_dict = json.loads(json_bytes)
print(json_dict,type(json_dict)) # {'username': 'xiao', 'age': 18} <class 'dict'>
return render(request,'02 ab_json.html')
(3)注意点
- contentType参数指定成:application/json
- 数据必须是真正的json格式数据
- django后端不会帮你处理json格式数据,需要你自己去request.body获取并处理
(4) Ajax发送json格式数据总结
- 前端:将数据封装为json格式;
- 前端:指定编码格式:
contentType: 'application/json'
; - 后端:手动处理json格式数据,对request.body接收的二进制数据进行处理:解码 + 反序列化。
三、ajax发送文件数据
大前提:ajax发送文件需要借助于js内置对象FormData
(1)前端
<p>username:<input type="text" name="username" id="d1"></p>
<p>password:<input type="password" name="password" id="d2"></p>
<p><input type="file" id="d3"></p>
<button id="d4" class="btn btn-success">点我</button>
<script>
// 点击按钮后端发送普通键值对和文件数量
$("#d4").on('click', function () {
// 1.需要先利用FormData内置对象
let formDataObj = new FormData(); # 既可以加普通键值对,也可以加文件
// 2、添加普通键值对
formDataObj.append('username', $("#d1").val());
formDataObj.append('password', $("#d2").val());
// 3.添加文件对象
formDataObj.append('myfile', $("#d3")[0].files[0]);
// 4.将对象基于ajax发送给后端
$.ajax({
url: '',
type: 'post',
data: formDataObj, // 直接将对象放在data后面即可
// ajax发送文件必须要指定的两个参数
contentType: false,
// 不需要使用任何编码,django后端能够自动识别formdata对象
processData: false,
// 告诉你的浏览器不要对你的数据进行任何处理
success: function (args) {
}
})
})
</script>
(2)后端
def ab_file(request):
if request.is_ajax():
if request.method == 'POST':
print('POST::>>', request.POST)
# 普通键值对放在了 request.POST 中
# POST::>> <QueryDict: {'username': ['quandsb'], 'password': ['111']}>
print('FILES::>>', request.FILES)
# 文件数据放在了 request.FILES 中
# FILES::>> <MultiValueDict: {'myfile': [<InMemoryUploadedFile: MySQL6.png (image/png)>]}>
return render(request, 'ab_file.html')
"""
个人理解:
request.POST:丰巢,一格一格的数据
request.FILES:菜鸟驿站,可取大件
request.body:传达室,自取自拿,一整个二进制数据
"""
(3)总结
- 需要利用内置对象FormData
- 添加普通的键值对
formDateObj.append('username', $('#d1').val());
formDateObj.append('password', $('#d2').val());
- 添加文件对象
formDateObj.append('myfile', $('#d3')[0].files[0])
- 需要指定两个关键性的参数
contentType:false, // 不需要使用任何编码,django后端能够自动识别formdata对象
processDate:false, // 告诉你的浏览器不要对你的数据进行任何处理
- django后端能够直接识别到formdata对象并且能够将内部的普通键值对自动解析并封装到request.POST中,文件数据自动解析并封装到request.FILES中
四、补充request方法判断ajax
request.is_ajax()
- 返回当前请求是否是ajax请求,返回布尔值
print(request.is_ajax())
# 正常浏览器网址回车提交的是 GET 请求 - 结果是False
# 当我们发送ajax请求后 - 结果是True