小谈DRF之解析器相关

5. 解析器 *

5.1 基于Django如何解析数据

5.1.1 request.POST中如何才能取到值?

要求:

  • 请求头的要求:
    • Content-Type : application/x-www-form-urlencoded
    • PS : 如果请求头中的Content-Type : application/x-www-form-urlencoded,request.POST中才有值,也就是说才会去request.body中去解析数据;
  • 数据格式的要求:
    • name=alex&age=18&gender=男

5.1.2 查看源码

先看我们写的代码:

# app01.urls.py
from django.conf.urls import url
from django.contrib import admin
from app01 import views

urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(), name='uuu'),
    url(r'^(?P<version>[v1|v2]+)/django/$', views.DjangoView.as_view(), name='ddd'),
]
# views.py
class DjangoView(APIView):

    def post(self, request, *args, **kwargs):
        from django.core.handlers.wsgi import WSGIRequest
        print(type(request._request))
        return HttpResponse('request.body和request.POST')

看如下图示:

image-20200913222959542

显示查看Django原生request(request._request)的类型,然后查看其(WSGIRequest)源码:

image-20200913223132958

找到他的GET,查看其源码:

image-20200913223253924

在GET的下面找到POST,查看_get_post的源码:

image-20200913223407768

在POST中找到_load_post_and_files()方法,查看其源码:

image-20200913223718601

5.1.3 request.body和request.POST中都有值的情况

情况一:form表单提交数据时,Django内部会自动转换数据并将Content-Type转换为application/x-www-form-urlencoded,所以request.body和request.POST中都有值。

<form method...>
	input...

</form>

情况二:ajax提交数据时,也是这样:Django内部会自动转换数据并将Content-Type转换为application/x-www-form-urlencoded,所以request.body和request.POST中都有值。

$.ajax({
	url:...
	type:POST,
	data:{name:alex, age:18} # 内部转化为:name=alex&age=18
})

5.1.4 request.body有值,但是request.POST中没有值的情况

情况一:数据格式对,但是Content-Type的类型不对;

$.ajax({
	url:...
	type:POST,
	headers:{'Content-Type': 'application/json'}
	data:{name:alex, age:18} # 内部转化为:name=alex&age=18
})

情况二:数据格式和Content-Type的类型都不对;

$.ajax({
	url:...
	type:POST,
	headers:{'Content-Type': 'application/json'}
	data:JSON.stringfy({name:alex, age:18}) # json数据:{name:alex,age:18}
})
# 如果要拿到数据,必须进行json.loads(request.body)

5.1.5 关于Django能否正常解析数据

因为Django内部只支持Content-Type:application/x-www-form-urlencoded并且数据类型为name=alex&age=18,所以必须要满足这两点,Django才能正常解析数据。

5.2 rest framework的解析器

rest framework的解析器就是对请求体的数据进行解析。

5.2.1 简单示例

from rest_framework.parsers import JSONParser

class ParserView(APIView):

    parser_classes = [JSONParser,]
    """
    JSONParser:表示只能解析Content-Type:application/json头
    """
    def post(self, request, *args, **kwargs):
        """
        允许用户发送JSON数据:
            1. Content-Type:application/json
            2. {"name":"alex","age":18}
        """
        print(request.data)
        return HttpResponse('parser')

利用postman进行测试:

image-20200913231156401

查看控制台结果:

image-20200913230405398

因为JSONParser只能解析Content-Type:application/json头,所以此时如果在postman中将Content-Type改为x-www-form-urlencoded的话,会报错,如图示:

image-20200913231410602

此时如果还想支持Content-Type:x-www-form-urlencoded的情况,需要修改视图代码,将FormParser也放在parser_classes中即可:

from rest_framework.parsers import JSONParser, FormParser

class ParserView(APIView):

    parser_classes = [JSONParser, FormParser]
    """
    JSONParser:表示只能解析Content-Type:application/json头
    FormParser:表示只能解析Content-Type:x-www-form-urlencoded头
    """
    def post(self, request, *args, **kwargs):
        """
        允许用户发送JSON数据:
            1. Content-Type:application/json
            2. {"name":"alex","age":18}
        :param request:
        :param args:
        :param kwargs:
        :return:
        """
        print(request.data)
        return HttpResponse('parser')

此时再用postman进行测试,如图所示:

image-20200913231844732

此时控制台显示结果也是正确的:

image-20200913231740866

最后说一下代码中的request.data

  • 如果没有这行代码的话,解析器工作了吗?
    • 没有工作,如果没有这行代码,我们只是构造了解析器但是没有使用;
  • 执行这行代码都有哪些步骤:
    • 获取用户的请求头;
    • 获取用户的请求体;
    • 根据用户的请求头和parser_classes = [JSONParser, FormParser]中的请求头对应;
    • parser_classes = [JSONParser, FormParser]中哪个合适,就用哪个类的对象去用户的请求体中解析数据;
    • 将解析后的数据赋值给request.data

5.2.2 源码分析

还是先从dispatch()方法入手:

image-20200914224546480

继续查看initialize_request()方法的源码:

image-20200914224649432

继续查看get_parsers()方法的源码:

image-20200914224730597

继续查看parser_classes的源码:

image-20200914224942594

将解析器的类封装到了Request后,就一直没有处理他。

直到我们需要获取request.data时才会触发解析器相关的一系列操作,所以我们从request.data的源码开始看,到底触发了那些操作。

查看request.data的源码:

image-20200914225258788

继续查看_load_data_and_files()方法的源码:

image-20200914225337848

继续查看self._parse()方法的源码:

image-20200914225835112

随便查看一个parser_classes中的一个类的源码就会有parse()方法,查看parse()方法的源码:

image-20200914230207981

5.2.3 总结

5.2.3.1 解析器的使用

解析器一般也是全局设置即可,如果有特殊需求的视图,可以单独添加parser_classes即可。

全局设置如下:

# settings.py
REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
    'DEFAULT_VERSION': 'v2', # 默认版本
    'ALLOWED_VERSIONS': ['v1', 'v2'], # 允许的版本
    'VERSION_PARAM': 'version', # 在浏览器中?version中的version,可以修改
	
    # 解析器的全局配置
    'DEFAULT_PARSER_CLASSES': ['rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser']
}
5.2.3.2 解析器的本质

解析器就是对用户请求体中的数据进行解析,依靠请求头中的Content-Type对请求体中的数据进行解析,解析到request.data中(由request.data触发)。

原文地址:https://www.cnblogs.com/richard_A/p/13887829.html