本系列文章中的上一篇文章:CBV (基于类的视图)源码解析
关于 Content-Type 的知识补充
当 Content-Type = “urlencoded” 的时候,前端将会把参数以 urlencoded 的形式发送给后端,比如传递两个参数 a = 1, b = 2,那么将会变成 a=1&b=2 的形式
而当 Content-Type = “json” 的时候,前端将会把参数以 json 的形式发送给后端,比如传递两个参数 a = 1, b = 2,那么将会变成 {"a": 1, "b": 2} 的 json 形式
而 django 中原生的 request.POST 只能获取到 urlencoded 形式的参数,不能解析 json 格式的数据
urls.py 中的代码
from .views import BookView urlpatterns = [ path('book/', BookView.as_view()), }
views.py 中 BookView 的代码
from rest_framework.views import APIView class BookView(APIView): # 当前段发送 GET 请求时,会执行 get 方法,方法名为对应的请求类型,不能随便修改 def get(self, request): return HttpResponse("APIView GET 请求....") # 当前段发送 POST 请求时,会执行 post 方法 def post(self, request): return HttpResponse("APIView POST 请求...") # 当前段发送 DELETE 请求时,会执行 delete 方法 def delete(self, request): return HttpResponse("APIView DELETE 请求....")
rest_framework.views.APIView 的源码(关键部分)
重写 django.views.View 中的 as_view() 方法
django.views.View 中的 as_view 的源码分析
@classmethod def as_view(cls, **initkwargs): # .... # 调用 父类(View)中的 as_view # 故此处的 view 的逻辑和父类一样,此处的 view 其实就是父类中的 view view = super().as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs # Note: session based authentication is explicitly CSRF validated, # all other authentication is CSRF exempt. return csrf_exempt(view)
重写 django.views.View 中的 dispatch() 方法
dispatch 方法中新构建的 request ,可以通过 request.query_params 获取 get 请求中的参数,而 post 请求时数据通过 request.data 获取
无论前端以什么样的 Content-Type 发送数据,APIView 都会将其解析成 QueryDict 形式的字典(<QueryDict: {'a': ['100'] }>),做到了数据格式的统一
def dispatch(self, request, *args, **kwargs): # .... # 重新构建 request # 新构建的 request 解决了原生的 request.POST 只能解析 urlencoded 的不足 request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: # 初始化:认证、权限、限流三件套 self.initial(request, *args, **kwargs) # 分发逻辑,即根据不同的请求相应不同的请求方法 # 此处的分发逻辑和父类中的 dispatch 差不多,可以参照上一篇文章 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 # request 是新构建的 request 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