上篇文章中:django之ajax我们给前端传一个字典数据需要先序列化成一个json字符串,前端使用JSON.parse来解析数据,如果我们在响应头里面加一个content_type='application/json’这个时候前端就不用在解析我们的json数据了,应为js中有自己的内部的解析器专门用来解析json数据
def test(request):
if request.method == 'GET':
return render(request,'test.html')
else:
username = request.POST.get('uname')
password = request.POST.get('pwd')
if username=='test' and password == '123':
ret = {'code':0,'success':'/app03/show_book/'}
return HttpResponse(json.dumps(ret),content_type='application/json')
else:
ret = {'code':1,'fail':'用户名或密码错误!!'}
return HttpResponse(json.dumps(ret),content_type='application/json')
前端HTML:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>JsonResponse</h1>
<form action="" method="post">
用户名:<input type="text" name="username" id="username">
用户名:<input type="password" name="password" id="password">
<input type="button" id="btn" value="确认">
<span style="color: red;font-size: 16px"></span>
</form>
<script src="{% static 'jquery.js' %}"></script>
<script>
$('#btn').click(function () {
$.ajax({
url: '/app03/test/',
type: 'post',
data: {
uname: $('#username').val(),
pwd: $('#password').val()
},
success: function (res) {
//var res_Str = JSON.parse(res); 注释掉了
if (res['code'] === 0) {
location.href = res['success']
} else if (res['code'] === 1) {
$('span').text(res['fail'])
}
}
})
})
</script>
</body>
</html>
结果还是一样能访问并没有报错,可以看到在我们的响应头里面有Content-Type: application/json就是我们视图函数里面设置的:
有没有一个方法可以将我们的数据序列化并且加上响应头呢,当然有,就是我们的JsonResponse,看名字就知道是返回一个json的数据,我们只需要该一个地方就行:
def test(request):
if request.method == 'GET':
return render(request,'test.html')
else:
username = request.POST.get('uname')
password = request.POST.get('pwd')
if username=='test' and password == '123':
ret = {'code':0,'success':'/app03/show_book/'}
# return HttpResponse(json.dumps(ret),content_type='application/json')
return JsonResponse(ret) #使用JsonResponse
else:
ret = {'code':1,'fail':'用户名或密码错误!!'}
# return HttpResponse(json.dumps(ret),content_type='application/json')
return JsonResponse(ret)
JsonResponse源码,可以看到JsonResponse已经给你做了设置请求头和序列化了:
def __init__(self, data, encoder=DjangoJSONEncoder, safe=True,
json_dumps_params=None, **kwargs):
if safe and not isinstance(data, dict):
raise TypeError(
'In order to allow non-dict objects to be serialized set the '
'safe parameter to False.'
)
if json_dumps_params is None:
json_dumps_params = {}
kwargs.setdefault('content_type', 'application/json') #设置请求头
data = json.dumps(data, cls=encoder, **json_dumps_params) #序列化
super(JsonResponse, self).__init__(content=data, **kwargs)
JsonResponse返回其他数据:
示例,发送一个ajax请求后端数据(列表),拿到数据之后展示在前端页面:
home页面:
def home(request):
return render(request, 'ajaxtes/home.html')
data页面:
def data_base(request):
li = [11,22,33,44,55,66]
#return JsonResponse(li)
return JsonResponse(li,safe=False)
报错:TypeError:In order to allow non-dict objects to be serialized set the safe parameter to False.
中文:为了允许非dict对象被序列化,请将safe参数设置为False。
前端HTML:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>JsonResponse返回列表数据</h1>
<ul>
</ul>
<script src="{% static 'jquery.js' %}"></script>
<script>
$.ajax({
url:"{% url 'app03:data_base' %}",
type:'get',
success:function (res) {
$.each(res,function (k,v) {
//console.log(k,v);
var res_Str = '' + v.toString() + '';
$('ul').append(res_Str)
})
}
})
</script>
</body>
</html>
如果传入的不是字典数据,需要加上safe=False参数
JsonResponse作用:
1.序列化数据
2.设置响应头kwargs.setdefault(‘content_type’, ‘application/json’)
content_type:前后端交互指定的一种消息格式
前端给后端传入json数据:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>JsonResponse</h1>
<ul>
</ul>
<script src="{% static 'jquery.js' %}"></script>
<script>
$.ajax({
url:"{% url 'app03:data_base' %}",
type:'post',
data:{k1:'v1',k2:'v2'}, #并不是json 默认是application/x-www-form-urlencoded类型
success:function (res) {
console.log(res)
}
})
</script>
</body>
</html>
后端视图函数:
def data_base(request):
li = [11,22,33,44,55,66]
print(request.POST) #
print(request.body) #b'k1=v1&k2=v2'
return JsonResponse(li,safe=False)
上面可以看到request.POST里面有数据 QueryDict类型,request.body里面是bytes类型的数据,django会从body里面那数据解析完成之后放到request.POST里面,浏览器默认请求类型都是application/x-www-form-urlencoded; charset=UTF-8类型:
为什么print(request.POST)就能拿到数据呢,这就是django有内置的解析器可以解析x-www-form-urlencoded; charset=UTF-8类型的数据,内置的解析器做了哪些事情,首先从请求头信息里面把请求头拿出来判断,如果’content_type’ == 'application/x-www-form-urlencoded;类型,就从请求体里面把数据拿出来(‘k1=v1&k2=v2’)然后解析,解析成一对一对的键值对并且放到request.POST中:
通过ajax发送json数据:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>JsonResponse</h1>
<ul>
</ul>
<script src="{% static 'jquery.js' %}"></script>
<script>
$.ajax({
url:"{% url 'app03:data_base' %}",
type:'post',
data:JSON.stringify({k1:'v1',k2:'v2'}), //将js中的字符串转换成json字符串
//data:{k1:'v1',k2:'v2'},
contentType:'application/json', //设置请求头
success:function (res) {
console.log(res)
}
})
</script>
</body>
</html>
后端接收的数据:
def data_base(request):
li = [11,22,33,44,55,66]
print(request.POST) # 里面没有数据
print(request.body) #b'{"k1":"v1","k2":"v2"}' 都在原始数据中
return JsonResponse(li,safe=False)
发送的json数据后端request.POST里面就没有数据了,反而都在body里面,这是为什么呢,因为django没有解析器可以解析application/json的数据类型,所以request.POST里面没有数据,如果是post请求需要从原始数据request.body中拿数据进行处理 get在get_full_path中拿原始数据,那发送过来的数据就没办法解析了吗?当然可以:
第一种办法:
print(eval(str(request.body,'utf-8'))['k1']) #v1
第二种办法:
推荐使用第二种方法:
print(json.loads(request.body)) {"k1":"v1","k2":"v2"}
什么是json:
总结:
相当于我有一个json方法,你有一个json方法,你给我发数据必须是json字符串的格式,那么你就需要将你的数据类型序列化为json的字符串,那么序列化的时候,就把你的数据序列化为了符合json标准的字符串,然后我接收到这个字符串之后,我通过我的json方法,将数据转换为我的语言支持的数据类型。在进行反序列化的时候,如果你的字符串不符合json的格式,那么反序列化的时候就会报错,所以只要你是通过json序列化成的字符串,都是能够json反序列化的,因为json序列化的时候,就把你的数据改为了符合json标准的字符串形式.
1.form表单上传文件:
<form action="" method="post" enctype="multipart/form-data">
头像:<input type="file" id="header_pic" name="header_pic">
用户名:<input type="text" name="username" id="username">
<input type="submit">
</form>
2.ajax上传文件:
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>文件上传</h1>
ajax上传文件:<input type="file" id="file">
ajax用户名:<input type="text" id="username">
<button id="btn">确认</button>
<script src="{% static 'jquery.js' %}"></script>
<script>
$('#btn').click(function () {
var res_File = new FormData(); //ajax携带文件数据的对象 它会将添加给它的键值对加工成formdata的类型
res_File.append('username',$('#username').val()); //添加键值的方法是append,注意写法,键和值之间是逗号
res_File.append('header_pic',$('#file')[0].files[0]); //$('#file')[0]:DOM对象 [0]:第一个
$.ajax({
url:"{% url 'app03:up_file' %}",
type:'post',
data:res_File, //将添加好数据的formdata放到data这里 也可以直接在这里写
processData:false, //固定写法 预处理操作 设置为False就是不处理数据
contentType:false, //固定写法 预处理操作 设置为False就是不设置内容类型
success:function (res) {
console.log(res)
}
})
})
</script>
</body>
</html>
后端代码:
def up_file(request):
if request.method == 'GET':
return render(request, 'ajaxtes/up.html')
else:
file_obj = request.FILES.get('header_pic')
from django.conf import settings
file_path = os.path.join(settings.BASE_DIR, 'statics','img', file_obj.name)
with open(file_path, 'wb') as f:
for chunk in file_obj.chunks():
//chunks():默认一次返回大小为经测试为65536B,也就是64KB,最大为2.5M, 可以设置每次读取大小,是一个生成器
f.write(chunk)
return HttpResponse('ok')
json是不能序列化日期数据类型,上面的对比图中可以看到json是没有日期类型的,这个需要借助一个模块JSONEncoder:
import json
from datetime import datetime, date
class JsonCustomEncoder(json.JSONEncoder): #继承json.JSONEncoder
def default(self, field):
if isinstance(field, datetime):
return field.strftime('%Y-%m-%d %H-%M-%S') #转换成字符串
elif isinstance(field, date):
return field.strftime('%Y-%m-%d')
else:
return json.JSONEncoder.default(self, field)
dic = {'name':'zhansgan','date_obj':datetime.now()} #里面有日期对象
ret = json.dumps(dic,cls=JsonCustomEncoder) #需要制定那个类来序列化
print(ret) #结果:{"name": "zhansgan", "date_obj": "2020-04-10 21-55-03"}