zoukankan      html  css  js  c++  java
  • 小谈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触发)。

  • 相关阅读:
    相对定位和绝对定位
    Html中常见的块级元素
    浮动的用法
    c#中质数判断
    函数
    asp.net Jquery+json 实现无刷新分页
    MS CRM2011 某个用户(团队)对某个实体的操作权限
    asp.net sitemap url动态参数
    MS CRM 2011 更改团队的业务部门
    MS CRM 2011 解决记录总数问题
  • 原文地址:https://www.cnblogs.com/richard_A/p/13887829.html
Copyright © 2011-2022 走看看