DRF源码分析

2021/6/17 20:56:06

本文主要是介绍DRF源码分析,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

APIView源码分析

# 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

Request对象

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)

 

图解

重新包装成一个request对象,以后再用request对象,就是新的request对象了

 

 

重写了getattr,通过反射,如果要取request.method,是去_request里面取

以后使用request对象,就像使用原来的request对象一样

request.data

request.query_params

APIView的initial(三大认证模块)

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源码分析

# 序列化多条,需要传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)
                )

图解

 



这篇关于DRF源码分析的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程