View源码分析:
views文件:
class MyView(View): def get(self,request): return HttpResponse(‘ok‘) def post(self,request): return HttpResponse(‘post‘)
urls文件:
urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘^$‘,views.MyView.as_view()), ]
View源码思路分析(这里拿重要的部分源码进行分析):
‘‘‘ 主要思路:View--》as_view --》as_view下的函数 当有路由匹配进来的时候,就会执行as_view这个方法 ‘‘‘ class View(object): http_method_names = [‘get‘, ‘post‘, ‘put‘, ‘patch‘, ‘delete‘, ‘head‘, ‘options‘, ‘trace‘] #继承classmethod @classonlymethod ‘‘‘ 这时会把我们在vies创建的MyView类,当作参数传递给as_view这个方法。 相当于as_view(MyView) **initkwargs是url匹配传递过来的参数:例如 url(r‘^$‘,views.MyView.as_view(age=1)), ‘‘‘ def as_view(cls, **initkwargs): """ Main entry point for a request-response process. """ def view(request, *args, **kwargs): ‘‘‘ self = cls(**initkwargs) 这一步是实例化一个对象,将我们传进来的类实例化赋值给self 相当于self=MyView(参数) ‘‘‘ self = cls(**initkwargs) if hasattr(self, ‘get‘) and not hasattr(self, ‘head‘): self.head = self.get self.request = request #将当前的request请求赋值给对象中的request. self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) return view def dispatch(self, request, *args, **kwargs): # request: 还是当前的请求对象 if request.method.lower() in self.http_method_names: ‘‘‘ 获取当前对象(MyView类的对象)的方法的内存地址 例如get请求:handler=getattr(self,‘get‘) ‘‘‘ handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs) #相当于执行get(request)
APIView源码分析:
views文件:
from rest_framework.views import APIView class MyAPIView(APIView): def get(self,request): #此时的request是drf重新封装后的request print(request._request) #原生request # 相当于request.GET data=request.query_params return HttpResponse(‘ok‘) def post(self,request): # 相当于request.POST post_data=request.data file_data=request.FILES
urls文件
urlpatterns = [ url(r‘^admin/‘, admin.site.urls), url(r‘apiview/‘,views.MyAPIView.as_view()) ]
APIView源码分析:
‘‘‘ #请求来了-》路由匹配上-》view(request)-》调用了self.dispatch(),这时执行的是apiview的dispatch,而不是view的dispatch ‘‘‘ class APIView(View): @classmethod def as_view(cls, **initkwargs): if isinstance(getattr(cls, ‘queryset‘, None), models.query.QuerySet): def force_evaluation(): raise RuntimeError( ‘Do not evaluate the `.queryset` attribute directly, ‘ ‘as the result will be cached and reused between requests. ‘ ‘Use `.all()` or call `.get_queryset()` instead.‘ ) cls.queryset._fetch_all = force_evaluation ‘‘‘ view = super().as_view(**initkwargs) 此时的view就View源码的as_view方法下的view 即调用父类(view)的as_view方法。 此时调用的dispatch方法是APIView的dispatch方法,而不是View的 执行顺序是从当前类(MyAPIView)中查找,找不到再从父类(APIView)中查找,再找不到再从APIView的父类View中找 ‘‘‘ view = super().as_view(**initkwargs) view.cls = cls view.initkwargs = initkwargs #只要继承了APIView,就不会再进行csrf认证 return csrf_exempt(view) #APIView的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 具体可以参照源码4 ‘‘‘ request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: #三大认证模块(具体看下面源码5) self.initial(request, *args, **kwargs) # 这部分跟View类中那部分一样。 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 #源码4、重新封装request的方法 def initialize_request(self, request, *args, **kwargs): 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 )
#源码5 APIView的initial方法 def initial(self, request, *args, **kwargs): # 做版本的控制 version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme # Ensure that the incoming request is permitted ‘‘‘ 认证组件:校验用户 - 游客、合法用户、非法用户 游客:代表校验通过,直接进入下一步校验(权限校验) 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验) 非法用户:代表校验失败,抛出异常,返回403权限异常结果 ‘‘‘ self.perform_authentication(request) ‘‘‘ 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色 认证通过:可以进入下一步校验(频率认证) 认证失败:抛出异常,返回403权限异常结果 ‘‘‘ self.check_permissions(request) ‘‘‘ 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s) 没有达到限次:正常访问接口 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问 ‘‘‘ self.check_throttles(request)
rest_framework下的Request类源码分析:
from rest_framework.request import Request class Request: def __init__(self, request, parsers=None, authenticators=None, negotiator=None, parser_context=None): assert isinstance(request, HttpRequest), ( ‘The `request` argument must be an instance of ‘ ‘`django.http.HttpRequest`, not `{}.{}`.‘ .format(request.__class__.__module__, request.__class__.__name__) ) self._request = request #原生request def __getattr__(self, attr): """ 通过反射,将原生request对象,以及属性和方法取出 """ try: return getattr(self._request, attr) except AttributeError: return self.__getattribute__(attr) ‘‘‘ 通过@property装饰器将data方法封装成属性 data方法:它是一个字典,post请求不管使用什么编码,传过来的数据,都在request.data ‘‘‘ @property def data(self): if not _hasattr(self, ‘_full_data‘): self._load_data_and_files() return self._full_data ‘‘‘ get请求的数据都在这里取 ‘‘‘ @property def query_params(self): """ More semantically correct name for request.GET. """ return self._request.GET ‘‘‘ 存文件数据 ‘‘‘ @property def FILES(self): if not _hasattr(self, ‘_files‘): self._load_data_and_files() return self._files