# from rest_framework.views import APIView # urls.py path('booksapiview/', views.BooksAPIView.as_view()), # 在这个地方应该写一个函数内存地址 # APIView的as_view方法(类的绑定方法) @classmethod def as_view(cls, **initkwargs): view = super().as_view(**initkwargs) # 调用父类(View)的as_view(**initkwargs) view.cls = cls # 参见下图补充 view.initkwargs = initkwargs # all other authentication is CSRF exempt. # 以后所有的请求都没有csrf的认证了,只要继承了APIView,就没有了csrf的认证 return csrf_exempt(view) # 请求来了--->路由匹配上--->View(request)--->调用了self.dispatch(),会执行APIview的dispatch # APIView的dispatch方法 def dispatch(self, request, *args, **kwargs): self.args = args self.kwargs = kwargs # self.initialize_request(request, *args, **kwargs) request是当次请求的request # request = self.initialize_request request是一个新的request对象 # 重新包装成一个request对象,以后再用request对象,就是新的request对象了 request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate? try: # 三大认证模块(详情参见下述内容) 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 views.py中 class BooksAPIView(APIView): def get(self, request): # request已经不是原生django的request了,是drf自己定义的request对象 # print(self.request) print(request.data) return HttpResponse('ok')
请求来了--->路由匹配上--->View(request)--->调用了self.dispatch(),会执行APIview的dispatch
ApiView的dispath
from rest_framework.request import Request # 以后只要继承了APLView,视图中的request对象,都是新的,也就是上面那个request的对象了 # 老的request在新的request._request # 以后使用request对象,就像使用之前的request是一模一样的(重写了__getattr__方法) def __getattr__(self, attr): try: # 通过反射,如果要取request.method,是去_request里面去取了 return getattr(self._request, attr) except AttributeError: return self.__getattribute__(attr) # request.data 感觉是个数据属性,其实是个方法 @property修饰了 # 它是一个字典,post请求不管使用什么编码,传过来的数据,都在request.data @property def data(self): if not _hasattr(self, '_full_data'): self._load_data_and_files() return self._full_data # get请求传过来的数据,从哪里取? request.GET 和 request.query_params都可以 @property def query_params(self): """ More semantically correct name for request.GET. """ return self._request.GET # views.py中 : print(request.query_params) # get请求,地址中的参数 # 原来在request.GET print(request.GET)
重写了getattr,通过反射,如果要取request.method,是去_request里面取
以后使用request对象,就像使用原来的request对象一样
def initial(self, request, *args, **kwargs): # 认证组件:校验用户 - 游客、合法用户、方法用户 # 游客:代表校验通过,直接进入下一步校验(权限校验) # 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验) # 非法用户:代表校验失败,抛出异常,返回403权限异常结果 self.perform_authentication(request) # 权限组件:校验用户权限 - 必须登录、所有用户、登录读写游客只读、自定义用户角色 # 认证通过:可以进入下一步校验(频率认证) # 认证失败:抛出异常,返回403权限异常结果 self.check_permissions(request) # 频率组件:限制视图接口被访问的频率次数 - 限制的条件(IP、id、唯一键)、频率周期时间(s、m、d)、频率的次数(3/s) # 没有达到限次:正常访问接口 # 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问 self.check_throttles(request)
# 序列化多条,需要传many=True # 对象的生成 ---> 先调用类的__new__方法,生成空对象 # 对象=类名(name=lqz),触发类的__init__() # 类的__new__方法控制对象的生成 def __new__(cls, *args, **kwargs): if kwargs.pop('many', False): return cls.many_init(*args, **kwargs) # 没有传many=True,走下面,正常的对象实例化 return super().__new__(cls, *args, **kwargs)
# 1 APIView ---> dispatch方法 ---> self.initial(request, *args, **kwargs) ---> 有认证,权限,频率 # 2 只读认证源码: self.perform_authentication(request) # 3 self.perform_authentication(request)就一句话request.user,需要去drf的Request对象中找user属性(方法) # 4 Request类中的user方法,刚开始来,没有user,走self._authenticate() # 5 核心:就是Request类的_authenticate(self): def _authenticate(self): # 遍历拿到一个个认证器,进行认证 # self.authenticators配置的一堆认证类产生的认证类对象组成的 list # # self.authenticators 是你在视图类中配置的一个个的认证类:authentication_classes = [认证类1,认证类2...] 对象的列表 for authenticator in self.authenticators: try: # 认证器(对象)调用认证方法authenticate(认证类对象self,request请求对象) # 返回值:登录的用户与认证的信息组成的 tuple # 该方法被try包裹,代表该方法会抛异常,抛异常就代表认证失败 user_auth_tuple = authenticator.authenticate(self) # 注意这个self是request对象 except exceptions.APIException: self._not_authenticated() raise # 返回值的处理 if user_auth_tuple is not None: self._authenticator = authenticator # 如果有返回值,就将用户 与 登录认证 分别保存到 request.user request.auth self.user, self.auth = user_auth_tuple return # 如果返回值user_auth_tuple为空,代表认证通过,但是没有 登录用户 与登录认证信息,代表游客 self._not_authenticated()
# APIView --->dispatch ---> initial ---> self.perform_authentication(request)(APIView的对象方法) def check_permissions(self, request): """ Check if the request should be permitted. Raises an appropriate exception if the request is not permitted. """ # 遍历权限对象列表得到一个个权限对象(权限器),进行权限认证 for permission in self.get_permissions(): # 权限类一定有一个has_permission权限方法,用来做权限认证的 # 参数:权限对象self、请求对象request、视图类对象 # 返回值:有权限返回True,无权限返回False if not permission.has_permission(request, self): self.permission_denied( request, message=getattr(permission, 'message', None), code=getattr(permission, 'code', None) )