Django CBV FBV跟Django Rest Framework CBV

284 阅读3分钟

1.Django FBV (function base view)


def index(request) :
    if request.method == 'GET': 
        pass 
    if request.method == 'POST': 
        pass 
    if request.method == 'DELETE': 
        pass 
    if request.method == 'PUT': 
        pass

启动项目访问 127.0.0.1:8000/index

使用get请求匹配成功会直接走get以此类推

2.Django CBV (Class base view)

CBV的本质其实还是FBV(上图)

(1)需要导入django View

image.png

(2)路由使用

image.png

(3)views定义类

image.png

(4)为什么是View?

点开继承查看路由调用的as_view()方法


@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(
                "The method name %s is not accepted as a keyword argument "
                "to %s()." % (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)
        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

    # __name__ and __qualname__ are intentionally left unchanged as
    # view_class should be used to robustly determine the name of the view
    # instead.
    view.__doc__ = cls.__doc__
    view.__module__ = cls.__module__
    view.__annotations__ = cls.dispatch.__annotations__
    # Copy possible attributes set by decorators, e.g. @csrf_exempt, from
    # the dispatch method.
    view.__dict__.update(cls.dispatch.__dict__)

    # Mark the callback if the view class is async.
    if cls.view_is_async:
        markcoroutinefunction(view)

    return view

发现return 的view函数 我们看view函数 return self.dispatch(request, *args, **kwargs)

接着我们再去找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)

发现本质却还是通过 request.method self.http_method_names 如果是get 其实就还是 self.get self是谁?

不就是你定义类吗?再去找get方法 其余都是一样的

3.drf的CBV(其实是封装的django的CBV)

上代码

(1).引入

image.png

(2)定义类

class drfcbv(APIView):
    def get(self, request):
        return Response({'status': 201, 'message': 'get'})

    def post(self, request):
        return Response({'status': 201, 'message': 'post'})

    def put(self, request):
        return Response({'status': 201, 'message': 'put'})

    def delete(self, request):
        return Response({'status': 201, 'message': 'delete'})

(3)定义路由

path('drfcbv/', views.login.as_view())

(4)解析源码

先看APIView的as_view()

@classmethod
def as_view(cls, **initkwargs):
    """
    Store the original class on the view function.

    This allows us to discover information about the view when we do URL
    reverse lookups.  Used for breadcrumb generation.
    """
    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.cls = cls
    view.initkwargs = initkwargs

    # Note: session based authentication is explicitly CSRF validated,
    # all other authentication is CSRF exempt.
    return csrf_exempt(view)

还是返回的view 我们就看这个view是啥?

view = super().as_view(**initkwargs)

super()是啥,父类!

我们看下APIView继承的view里面的as_view

wc

@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(
                "The method name %s is not accepted as a keyword argument "
                "to %s()." % (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)
        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

    # __name__ and __qualname__ are intentionally left unchanged as
    # view_class should be used to robustly determine the name of the view
    # instead.
    view.__doc__ = cls.__doc__
    view.__module__ = cls.__module__
    view.__annotations__ = cls.dispatch.__annotations__
    # Copy possible attributes set by decorators, e.g. @csrf_exempt, from
    # the dispatch method.
    view.__dict__.update(cls.dispatch.__dict__)

    # Mark the callback if the view class is async.
    if cls.view_is_async:
        markcoroutinefunction(view)

    return view

这不就是Django的view吗

啊? 那我要这drf的cbv干嘛????

嘿嘿,下次在告诉你