• REST-Framework: 解析器


    Rest-Framework中的解析器和响应器是对应的,分别对客户端的请求和服务器的响应相对应做处理

    一 解析器的作用

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

    有application/json,x-www-form-urlencoded,form-data等格式, 可以自己自行配置支持或者不支持哪种格式, 一般在实际的生产环境中用json一种数据格式进行数据交互就够了, 如果需要form-data来进行文件处理,再将该格式加入到解析器中即可

    二 全局使用解析器

    setting里

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

    路由:

     
    urlpatterns = [
     
    url(r'test/', TestView.as_view()),
     
    ]

    视图函数:

     
    from rest_framework.views import APIView
     
    from rest_framework.response import Response
     
     
     
    class TestView(APIView):
     
    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请求,响应内容')
     
     
     
    def put(self, request, *args, **kwargs):
     
    return Response('PUT请求,响应内容')

    三 局部使用解析器

    a. 仅处理请求头content-type为application/json的请求体

     
    from django.conf.urls import url, include
     
    from web.views.s5_parser import TestView
     
     
     
    urlpatterns = [
     
    url(r'test/', TestView.as_view(), name='test'),
     
    ]
     
    #!/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
     
     
     
     
     
    class TestView(APIView):
     
    parser_classes = [JSONParser, ]
     
     
     
    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请求,响应内容')
     
     
     
    def put(self, request, *args, **kwargs):
     
    return Response('PUT请求,响应内容')

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

     
    from django.conf.urls import url, include
     
    from web.views import TestView
     
     
     
    urlpatterns = [
     
    url(r'test/', TestView.as_view(), name='test'),
     
    ]
     
    
     
    #!/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 FormParser
     
     
     
     
     
    class TestView(APIView):
     
    parser_classes = [FormParser, ]
     
     
     
    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请求,响应内容')
     
     
     
    def put(self, request, *args, **kwargs):
     
    return Response('PUT请求,响应内容')

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

     
    from django.conf.urls import url, include
     
    from web.views import TestView
     
     
     
    urlpatterns = [
     
    url(r'test/', TestView.as_view(), name='test'),
     
    ]
     
    #!/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 MultiPartParser
     
     
     
     
     
    class TestView(APIView):
     
    parser_classes = [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请求,响应内容')
     
     
     
    def put(self, request, *args, **kwargs):
     
    return Response('PUT请求,响应内容')
     
    <!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>

    d. 仅上传文件

     
    from django.conf.urls import url, include
     
    from web.views import TestView
     
     
     
    urlpatterns = [
     
    url(r'test/(?P<filename>[^/]+)', TestView.as_view(), name='test'),
     
    ]
     
    #!/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 FileUploadParser
     
     
     
     
     
    class TestView(APIView):
     
    parser_classes = [FileUploadParser, ]
     
     
     
    def post(self, request, filename, *args, **kwargs):
     
    print(filename)
     
    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请求,响应内容')
     
     
     
    def put(self, request, *args, **kwargs):
     
    return Response('PUT请求,响应内容')
     
    <!DOCTYPE html>
     
    <html lang="en">
     
    <head>
     
    <meta charset="UTF-8">
     
    <title>Title</title>
     
    </head>
     
    <body>
     
    <form action="http://127.0.0.1:8000/test/f1.numbers" method="post" enctype="multipart/form-data">
     
    <input type="text" name="user" />
     
    <input type="file" name="img">
     
     
     
    <input type="submit" value="提交">
     
     
     
    </form>
     
    </body>
     
    </html>

    e. 同时多个Parser

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

     
    from django.conf.urls import url, include
     
    from web.views import TestView
     
     
     
    urlpatterns = [
     
    url(r'test/', TestView.as_view(), name='test'),
     
    ]
    

      

     
    #!/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请求,响应内容')
     
     
     
    def put(self, request, *args, **kwargs):
     
    return Response('PUT请求,响应内容')

    四 源码分析

     
    # 1 在调用request.data时,才进行解析,由此入手
     
    @property
     
    def data(self):
     
    if not _hasattr(self, '_full_data'):
     
    self._load_data_and_files()
     
    return self._full_data
     
     
     
    # 2 查看self._load_data_and_files()方法---->self._data, self._files = self._parse()
     
     
     
    def _parse(self):
     
    #用户请求头里content_type的值
     
    media_type = self.content_type
     
     
     
    #self.parsers 就是用户配置的parser_classes = [FileUploadParser,FormParser ]
     
    #self里就有content_type,传入此函数
     
    parser = self.negotiator.select_parser(self, self.parsers)
     
     
     
    # 3 查看self.negotiator.select_parser(self, self.parsers)
     
    def select_parser(self, request, parsers):
     
    #同过media_type和request.content_type比较,来返回解析器,然后调用解析器的解析方法
     
    #每个解析器都有media_type = 'multipart/form-data'属性
     
    for parser in parsers:
     
    if media_type_matches(parser.media_type, request.content_type):
     
    return parser
     
    return None
     
     
     
    # 4 最终调用parser的解析方法来解析parsed = parser.parse(stream, media_type, self.parser_context)
     
    1 Request实例化,parsers=self.get_parsers()
     
    Request(
     
    request,
     
    parsers=self.get_parsers(),
     
    authenticators=self.get_authenticators(),
     
    negotiator=self.get_content_negotiator(),
     
    parser_context=parser_context
     
    )
     
    2 get_parsers方法,循环实例化出self.parser_classes中类对象
     
    def get_parsers(self):
     
    return [parser() for parser in self.parser_classes]
     
     
     
    3 self.parser_classes 先从类本身找,找不到去父类找即APIVIew 中的
     
    parser_classes = api_settings.DEFAULT_PARSER_CLASSES
     
    4 api_settings是一个对象,对象里找DEFAULT_PARSER_CLASSES属性,找不到,会到getattr方法
     
    def __getattr__(self, attr):
     
    if attr not in self.defaults:
     
    raise AttributeError("Invalid API setting: '%s'" % attr)
     
     
     
    try:
     
    #调用self.user_settings方法,返回一个字典,字典再取attr属性
     
    val = self.user_settings[attr]
     
    except KeyError:
     
    # Fall back to defaults
     
    val = self.defaults[attr]
     
     
     
    # Coerce import strings into classes
     
    if attr in self.import_strings:
     
    val = perform_import(val, attr)
     
     
     
    # Cache the result
     
    self._cached_attrs.add(attr)
     
    setattr(self, attr, val)
     
    return val
     
    5 user_settings方法 ,通过反射去setting配置文件里找REST_FRAMEWORK属性,找不到,返回空字典
     
    @property
     
    def user_settings(self):
     
    if not hasattr(self, '_user_settings'):
     
    self._user_settings = getattr(settings, 'REST_FRAMEWORK', {})
     
    return self._user_settings
     
    每天逼着自己写点东西,终有一天会为自己的变化感动的。这是一个潜移默化的过程,每天坚持编编故事,自己不知不觉就会拥有故事人物的特质的。 Explicit is better than implicit.(清楚优于含糊)
  • 相关阅读:
    QML用Qt.labs.settings实现保存用户设置
    周练1
    Django的Hello World
    python 笔记
    Qt Creator 搭配Git 版本控制
    Windows系统下在Git Bash中把文件内容复制到剪贴板的命令
    【转】Qt之JSON保存与读取
    Qt Creator 中文编译失败 怎么办
    Treap树 笔记
    【POJ1037】A decorative fence(DP)
  • 原文地址:https://www.cnblogs.com/kylin5201314/p/13967141.html
Copyright © 2020-2023  润新知