Django rest framework(5)----解析器
解析器的主要作用:对用户请求体中的数据进行解析
解析器前戏
有时候我们在接受前端传送的值的时候,会存在这样一个奇怪的现象使用request.body可以取到值,而使用request.POST的时候去不到值,基于这样的情况,究竟是如何造成的呢?
追了以下源码发现 把request.body 中的值转换成 POST 需要满足以下的两个条件,也就是说必须满足以下两个条件,才可以使用request.POST接受值,否则只能使用request.body
1. 请求头要求: Content-Type: application/x-www-form-urlencoded PS: 如果请求头中的 Content-Type: application/x-www-form-urlencoded,request.POST中才有值(去request.body中解析数据)。 2. 数据格式要求: name=alex&age=18&gender=男
PS 以上的两个条件缺一不可
部分源码如下
一般在那些地方默认可以使用request.POST 接受的呢
表单提交:
a. form表单提交 <form method...> input... </form>
ajax 提交的数据。headers content-type使用默认类型的
$.ajax({ url:... type:POST, data:{name:alex,age=18} # 内部转化 name=alex&age=18&gender=男 })
这样的情况是 request.body有值;request.POST无值,如果我们需要取值的话可以这样做 json.loads(request.body)
$.ajax({ url:... type:POST, headers:{'Content-Type':"application/json"} data:JSON.stringfy({name:alex,age=18}) # {name:alex,age:18...} })
以上的情况判断去使用的时候,我们需要去辨别 headers 中的请求类型,那么有没有一种好的方式,使一切变得简单一些呢,当然下面直接上代码有一个清晰的认识在来追踪它的源码
restframework--解析器使用
类视图代码如下:
from rest_framework.parsers import JSONParser,FormParser class ParserView(APIView): parser_classes = [JSONParser,FormParser,] """ JSONParser:表示只能解析content-type:application/json头 JSONParser:表示只能解析content-type:application/x-www-form-urlencoded头 """ def post(self,request,*args,**kwargs): """ 允许用户发送JSON格式数据 a. content-type: application/json b. {'name':'alex',age:18} :param request: :param args: :param kwargs: :return: """ """ 1. 获取用户请求 2. 获取用户请求体 3. 根据用户请求头 和 parser_classes = [JSONParser,FormParser,] 中支持的请求头进行比较 4. JSONParser对象去请求体 5. request.data """ print(request.data) return HttpResponse('ParserView')
添加url
url(r'parser/$', views.ParserView.as_view()),
发送 表单的数据
后台打印的数据如下
发送json类型的数据
后台接受打印的数据如下
源码流程
入口 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, # parsers=self.get_parsers(), # authenticators=self.get_authenticators(), # negotiator=self.get_content_negotiator(), # parser_context=parser_context # ) #request(原始request,[BasicAuthentications对象,]) #获取原生request,request._request #获取认证类的对象,request.authticators #1.封装request request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: #2.认证 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
initialize_request 获取所有解析器
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) return Request( request, parsers=self.get_parsers(), #获取所有的解析器 authenticators=self.get_authenticators(), #[BasicAuthentication(),],把所有的认证类对象封装到request里面了 negotiator=self.get_content_negotiator(), parser_context=parser_context )
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]
parser_classes
同样我们可以在settings里面全局配置,我们一般使用的就是全局的配置
REST_FRAMEWORK = { #版本 "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning", #解析器 "DEFAULT_PARSER_CLASSES":["rest_framework.parsers.JSONParser","rest_framework.parsers.FormParser"] }