zoukankan      html  css  js  c++  java
  • rest framework 之解析器

    一、示例

    1、api/urls.py

    from django.urls import path, re_path
    from api.views import UserView, ParserView
    
    urlpatterns = [
        # path('users/', UserView.as_view()),
        re_path('(?P<version>[v1|v2]+)/users/', UserView.as_view(), name='api_user'),
    
        path('parser/', ParserView.as_view(), name='api_parer'),		# 添加这句
    ]
    

    2、api/views.py

    • JSONParser:只能解析content-type:application/json的头
    • FormParser:只能解析content-type:application/x-www-form-urlencoded的头
    from rest_framework.parsers import JSONParser, FormParser
    
    
    class ParserView(APIView):
        parser_classes = [JSONParser, FormParser]
    
        def post(self, request, *args, **kwargs):
            print(request.data)
    
            return HttpResponse('解析')
    

    3、使用 postman 发送 json 数据测试后台是否能解析:

    (1)、设置为 post 方式,headers 中添加数据类型为 json

    1561876642957

    (2)、body 中选择 raw,然后选择 json 类型,最后就是在空白处构建要发送的 json 数据(记得是双引号):

    1561876682025

    后台结果:

    1561876744825

    如果是 content-type:application/x-www-form-urlencoded 类型数据,不需要设置请求头,默认就是。但是 body 中需要设置为 x-www-form-urlencoded

    二、源码分析

    1、dispatch()

    def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        # 对原生的 request 对象进行加工,丰富了
        # request= Request(request,parsers=self.get_parsers(),authenticators=self.get_authenticators(),negotiator=self.get_content_negotiator(),parser_context=parser_context)
        # 第一个参数为原生的 request 对象,封装原生 request
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?
    
        try:
    
            self.initial(request, *args, **kwargs)
    
            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed
    
                response = handler(request, *args, **kwargs)
    
        except Exception as exc:
            response = self.handle_exception(exc)
    
            self.response = self.finalize_response(request, response, *args, **kwargs)
            return self.response
    

    2、initialize_request()

    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object. 封装原生 request 对象
        """
        parser_context = self.get_parser_context(request)
    
        return Request(
            request,
            # 获取所有解析器
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )
    

    3、get_parsers()

    def get_parsers(self):
        """
        Instantiates and returns the list of parsers that this view can use.
        返回次视图可以使用的解析器列表
        """
        return [parser() for parser in self.parser_classes]
    

    4、parser_classes

    class APIView(View):
    
        # The following policies may be set at either globally, or per-view.
        renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
        # 从 settings 中获取解析器
        parser_classes = api_settings.DEFAULT_PARSER_CLASSES
    
        # Allow dependency injection of other settings to make testing easier.
        settings = api_settings
    

    5、全局配置解析器 settings

    REST_FRAMEWORK = {
        # 解析器
        "DEFAULT_PARSER_CLASSES":["rest_framework.parsers.JSONParser","rest_framework.parsers.FormParser"]
    }
    

    源码流程图

    1561877753625


    根据请求头 content-type 选择对应的解析器就请求体内容进行处理。

    三、仅处理请求头 content-type 为 application/json 的请求体

    1、urls.py

    from django.urls import path, re_path, include
    from api.views import TestView2
    
    urlpatterns = [
        re_path(r'(?P<version>[v1|v2]+)/test2', TestView2.as_view()),
    ]
    

    2、views.py

    rom rest_framework.views import APIView
    from rest_framework.parsers import JSONParser, FormParser
    from rest_framework.response import Response
    
    
    class TestView2(APIView):
        parser_classes = [JSONParser]
    
        def post(self, request, *args, **kwargs):
            print(request.content_type)    # application/json
    
            # 获取请求值,并发 JSONParser  处理
            print(request.data)     # {'name': 'rose', 'age': 18}
    
            # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
            print(request.POST)         # <QueryDict: {}>
            print(request.FILES)        # <MultiValueDict: {}>
    
            return Response('响应内容')
    

    四、仅处理请求头 content-type 为 application/x-www-form-urlencoded 的请求体

    1、urls.py

    from django.urls import path, re_path, include
    from api.views import TestView2
    
    urlpatterns = [
        re_path(r'(?P<version>[v1|v2]+)/test2', TestView2.as_view()),
    ]
    

    2、views.py

    rom rest_framework.views import APIView
    from rest_framework.parsers import JSONParser, FormParser
    from rest_framework.response import Response
    
    
    class TestView2(APIView):
        parser_classes = [FormParser]
    
        def post(self, request, *args, **kwargs):
            print(request.content_type)    # application/x-www-form-urlencoded
    
            # 获取请求值,并发 JSONParser  处理
            print(request.data)     # <QueryDict: {'123': ['']}>
    
            # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
            print(request.POST)         # <QueryDict: {'123': ['']}>
            print(request.FILES)        # <MultiValueDict: {}>
    
            return Response('响应内容')
    

    五、仅处理请求头content-type为multipart/form-data的请求体

    1、urls.py

    from django.urls import path, re_path, include
    from api.views import TestView2
    
    urlpatterns = [
        re_path(r'(?P<version>[v1|v2]+)/test2', TestView2.as_view()),
    ]
    

    2、views.py

    rom rest_framework.views import APIView
    from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
    from rest_framework.response import Response
    
    
    class TestView2(APIView):
        parser_classes = [MultiPartParser]
    
        def post(self, request, *args, **kwargs):
            print(request.content_type)    # multipart/form-data
    
            # 获取请求值,并发 JSONParser  处理
            print(request.data)    
    
            # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
            print(request.POST)         
            print(request.FILES)        
    
            return Response('响应内容')
    

    3、upload.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
        <input type="text" name="user" />
        <input type="file" name="img">
    
        <input type="submit" value="提交">
    
    </form>
    </body>
    </html>
    

    六、仅上传文件

    1、urls.py

    from django.urls import path, re_path, include
    from api.views import TestView2
    
    urlpatterns = [
        re_path(r'(?P<version>[v1|v2]+)/test2', TestView2.as_view()),
    ]
    

    2、views.py

    rom rest_framework.views import APIView
    from rest_framework.parsers import JSONParser, FormParser, MultiPartParser, FileUploadParser
    from rest_framework.response import Response
    
    
    class TestView2(APIView):
        parser_classes = [FileUploadParser]
    
        def post(self, request, *args, **kwargs):
            print(request.content_type)    
    
            # 获取请求值,并发 JSONParser  处理
            print(request.data)    
    
            # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
            print(request.POST)         
            print(request.FILES)        
    
            return Response('响应内容')
    

    3、upload.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    <form action="http://127.0.0.1:8000/test/" method="post" enctype="multipart/form-data">
        <input type="text" name="user" />
        <input type="file" name="img">
    
        <input type="submit" value="提交">
    
    </form>
    </body>
    </html>
    

    七、其他

    多个 parser

    当同时使用多个 parser 时,rest framework 会根据请求头 content-type 自动进行比对,并使用对应 parser

    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.parsers import JSONParser, FormParser, MultiPartParser
    
    
    class TestView(APIView):
        parser_classes = [JSONParser, FormParser, MultiPartParser, ]
    
        def post(self, request, *args, **kwargs):
            print(request.content_type)
    
            # 获取请求的值,并使用对应的JSONParser进行处理
            print(request.data)
            # application/x-www-form-urlencoded 或 multipart/form-data时,request.POST中才有值
            print(request.POST)
            print(request.FILES)
            return Response('POST请求,响应内容')
    

    全局使用

    settings.py

    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser'
            'rest_framework.parsers.FormParser'
            'rest_framework.parsers.MultiPartParser'
        ]
    
    }
    
    

    Tips: 个别特殊的值可以通过Django的request对象 request._request 来进行获取

    总结

    • JSONParser,解析数据类型:content-type:application/json
    • FormParser,解析数据类型:content-type:application/x-www-form-urlencoded
    • 支持全局配置解析器类型
  • 相关阅读:
    Selenium自动化测试-unittest单元测试框架
    Python 面向对象
    【新手总结】在.Net项目中使用Redis作为缓存服务
    asp.net性能优化之使用Redis缓存(入门)
    浅谈MVC、MVP、MVVM架构模式的区别和联系
    jquery uploadify在谷歌浏和火狐下无法上传的解决方案(.Net版)
    [翻译]NUnit---Action Attributes(八)
    [翻译]NUnit---String && Collection && File && Directory Assert (七)
    [翻译]NUnit---Exception && Utility Methods (六)
    [翻译]NUnit---Condition Asserts && Comparisons Asserts && Type Asserts (五)
  • 原文地址:https://www.cnblogs.com/midworld/p/11380172.html
Copyright © 2011-2022 走看看