Django rest framework源码阅读(2)----CBV模式

CBV基于反射实现根据请求方式不同,执行不同的方法

  • CBV 类需要继承 rest franework 提供的 APIView,APIView 继承自 Django的 views.generic.base.View,所以CBV继承自Django的View。请求到达Django会先执行Django中间件里的方法,然后进行进行路由匹配,在路由匹配完成后,会执行CBV类中的as_view方法,CBV中并没有定义as_view方法,而是执行Django的View类中的as_view方法。
  • View类提供了as_view()类方法,注意,这个方法只能当作类方法使用,不能用在实例上,它返回一个内方法view(),在这个方法中,做的事情就是dispatch的事情,根据请求的方法,调用相应的方法去处理请求,如果你发送了一个GET请求,那么在view()方法中就会分发到get()方法中去处理。View类就主要封装了这个功能,这个功能是最高层的抽象,所有的view都需要有这个特性。
class View:
    """
    Intentionally simple parent class for all views. Only implements
    dispatch-by-method and simple sanity checking.
    """

    http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']

    def __init__(self, **kwargs):
        """
        Constructor. Called in the URLconf; can contain helpful extra
        keyword arguments, and other things.
        """
        # Go through keyword arguments, and either save their values to our
        # instance, or raise an error.
        for key, value in kwargs.items():
            setattr(self, key, value)

    @classonlymethod
    def as_view(cls, **initkwargs):
        """Main entry point for a request-response process."""
        for key in initkwargs:
            if key in cls.http_method_names:
                raise TypeError("You tried to pass in the %s method name as a "
                                "keyword argument to %s(). Don't do that."
                                % (key, cls.__name__))
            if not hasattr(cls, key):
                raise TypeError("%s() received an invalid keyword %r. as_view "
                                "only accepts arguments that are already "
                                "attributes of the class." % (cls.__name__, key))

        def view(request, *args, **kwargs):
            self = cls(**initkwargs)
            if hasattr(self, 'get') and not hasattr(self, 'head'):
                self.head = self.get
            self.setup(request, *args, **kwargs)
            if not hasattr(self, 'request'):
                raise AttributeError(
                    "%s instance has no 'request' attribute. Did you override "
                    "setup() and forget to call super()?" % cls.__name__
                )
            return self.dispatch(request, *args, **kwargs)
        view.view_class = cls
        view.view_initkwargs = initkwargs

        # take name and docstring from class
        update_wrapper(view, cls, updated=())

        # and possible attributes set by decorators
        # like csrf_exempt from dispatch
        update_wrapper(view, cls.dispatch, assigned=())
        return view
  • 源码分析
    • 从View的源码可以看出,在View类中,先定义了http请求的八种方法http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace']在as_view方法中进行判断,如果请求的方法没在http_method_names中,则会抛出异常。
    • 这里的cls实际上指的是自定义的CBV类,接着as_view方法中又定义view方法,在view方法中对CBV类进行实例化(self = cls(**initkwargs)),得到self对象。
    • 然后在self对象中封装浏览器发送的request请求,最后又调用了self对象中的dispatch方法,并返回dispatch方法的值来对request进行处理。
    • 由于self对象就是CBV实例化得到,所以会先执行自定义的CBV类中的dispatch方法。如果CBV类中没有定义dispatch方法则执行Django的View中的dispatch方法。
    def dispatch(self, request, *args, **kwargs):
        # Try to dispatch to the right method; if a method doesn't exist,
        # defer to the error handler. Also defer to the error handler if the
        # request method isn't on the approved list.
        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
        return handler(request, *args, **kwargs)
  • 源码分析
    • 在dispatch方法中,把request.method转换为小写再判断是否在定义的http_method_names中,如果request.method存在于http_method_names中,则使用getattr反射的方式来得到handler。
    • 在这里的dispatch方法中,self指的是自定义的CBV类实例化得到的对象。
    • 从CBV类中获取request.method对应的方法,再执行CBV中的方法并返回,可以知道如果在Django项目中使用CBV的模式,实际上调用了getattr的方式来执行获取类中的请求方法对应的函数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值