Django之ajax、form表单上传文件

一.JsonResponse

上篇文章中: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 = '<li>' + v.toString() + '</li>';
                $('ul').append(res_Str)
            })
        }
    })
</script>
</body>
</html>

如果传入的不是字典数据,需要加上safe=False参数
JsonResponse作用:
1.序列化数据
2.设置响应头kwargs.setdefault(‘content_type’, ‘application/json’)

二.content_type

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)      #<QueryDict: {'k1': ['v1'], 'k2': ['v2']}>
    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中:<QueryDict: {‘k1’: [‘v1’], ‘k2’: [‘v2’]}>在这里插入图片描述
通过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)      #<QueryDict: {}>   里面没有数据
    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:

  1. JSON 指的是 JavaScript 对象表示法(JavaScript Object Notation)
  2. JSON 是轻量级的文本数据交换格式
  3. JSON 独立于语言 *
  4. JSON 具有自我描述性,更易理解
  5. JSON 使用 JavaScript 语法来描述数据对象,但是 JSON 仍然独立于语言和平台。JSON 解析器和 JSON库支持许多不同的编程语言。
    在这里插入图片描述
    json数据类型和python数据类型的对比,源码中有对比图:
    在这里插入图片描述
    前端中解析json数据的方法:json.parse()
    前端中序列化json数据的方法:json.stringify()
    python中序列化成json字符串:json.dumps()
    python中反序列化成json字符串:json.loads()

总结:
相当于我有一个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是不能序列化日期数据类型,上面的对比图中可以看到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"}

猜你喜欢

转载自blog.csdn.net/qq_39253370/article/details/105427564