drf的解析模块(了解) - 服务的对象是数据包数据
一、能够在视图类中经过parser_classes类属性对该视图的数据包解析作配置 - 局部配置
二、能够在项目的配置文件的drf配置中经过DEFAULT_PARSER_CLASSES对该视图的数据包解析作配置 - 全局配置html
核心:请求的数据包格式会有三种(json、urlencoded、form-data),drf默认支持三种数据的解析,能够全局或局部配置视图类具体支持的解析方式python
,系统默认三种都是支持的,主要是设置用户请求的数据包,进行配置,要求只要一种数据,方便使用。web
根据请求头 content-type 选择对应的解析器对请求体内容进行处理。django
有application/json,x-www-form-urlencoded,form-data等格式json
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请求,响应内容')
from rest_framework.parsers import JSONParser # json格式 from rest_framework.parsers import FormParser from rest_framework.parsers import MultiPartParser # JSONParser: json数据 # FormParser: urlencoded # MultiPartParser:form-data class Book(APIView): parser_classes = [JSONParser,] def get(self, request, *args, **kwargs): return Response('get ok') def post(self, request, *args, **kwargs): print(request._request.GET) print(request.data) print(request.data.dict()) # print(request.data.dict()) return Response({ 'status': 0, 'msg': "post ok" })
parser_classes = [FormParser]
parser_classes = [MultiPartParser,]
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> <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>
当同时使用多个parser时,rest framework会根据请求头content-type自动进行比对,并使用对应parserapi
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请求,响应内容')
解析模块源码分析
一、APIView的dispatch方法:self.initialize_request(request, *args, **kwargs)内部还提供了数据解析
二、self.get_parser_context(request)提供要解析的数据,self.get_parsers()提供解析的类对象(内部从配置中找解析类)app
入口:dispatch()方法函数
request = self.initialize_request(request, *args, **kwargs)
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ # 准备要解析的内容 parser_context = self.get_parser_context(request) return Request( request, # 解析模块,在封装原生的request的时候,将数据一并解析 parsers=self.get_parsers(),#获取解析类 authenticators=self.get_authenticators(),# 处理请求 negotiator=self.get_content_negotiator(),# 处理导航的 parser_context=parser_context )
解析的内容源码分析
def get_parser_context(self, http_request): """ Returns a dict that is passed through to Parser.parse(), as the `parser_context` keyword argument. """ # Note: Additionally `request` and `encoding` will also be added # to the context by the Request object. # 压迫被解析的内容 return { 'view': self, 'args': getattr(self, 'args', ()), 'kwargs': getattr(self, 'kwargs', {}) }
def get_parsers(self): """ Instantiates and returns the list of parsers that this view can use. """ # 可以完成局部和全局的 配置 return [parser() for parser in self.parser_classes]
# 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