DRF学习——CBV与FBV

一、简介

本文章首先通过使用CBV和FBV两种不同的编写方式实现相同功能后,通过介绍as.view()的源码来介绍CBV的本质

二、代码

①项目目录结构

 ②view.py

from django.http import JsonResponse
from django.views import View

# FBV
def auth(request):
    # 如果请求方式为GET
    if request.method == "GET":  
        return JsonResponse({'status': True, 'message': "GET"})
    # 如果请求方式为POST
    elif request.method == "POST":  
        return JsonResponse({'status': True, 'message': "POST"})
     # 如果请求方式为其他
    return JsonResponse({'status': True, 'message': "other"}) 
# CBV
class UserView(View):
    def get(self, request):
        return JsonResponse({'status': True, 'message': "GET"})

    def post(self, request):
        return JsonResponse({'status': True, 'message': "POST"})

    def delete(self, request):
        return JsonResponse({'status': True, 'message': "DELETE"})

    def put(self, request):
        return JsonResponse({'status': True, 'message': "PUT"})

③urls.py

from django.urls import path
from app01 import views

urlpatterns = [
    # path('admin/', admin.site.urls),
    path('auth/', views.auth),      # FBV
    path('user/', views.UserView.as_view()),        # CBV
]

三、Postman测试API接口

首先需要将settings..py中的'django.middleware.csrf.CsrfViewMiddleware'注释掉(防止django做csrf校验)

①FBV方式

get请求

post请求 

patch请求

 ②CBV方式

get请求

post请求 

四、as_view()

通过测试接口,CBV和FBV都可实现相同的返回,表面的区别就在于FBV用的def定义函数,而CBV用的class定义类,且在urls.py中CBV在类名后面多跟了as_view()

通过url的定义,可以知道当访问/user/这个api接口时,会执行UserView中的as_view()的返回结果,重点就在于as.view(),弄清楚as.view()实现的具体功能,即可明白CBV的本质

path('user/', views.UserView.as_view()),        # CBV

UserView

# django_CBV
class UserView(View):
    def get(self, request):
        return JsonResponse({'status': True, 'message': "GET"})

    def post(self, request):
        return JsonResponse({'status': True, 'message': "POST"})

    def delete(self, request):
        return JsonResponse({'status': True, 'message': "DELETE"})

    def put(self, request):
        return JsonResponse({'status': True, 'message': "PUT"})

从上面代码可知,UserView中并没有as_view,因此需要进入父类View中寻找

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

    # 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在as_view中已经定义了,因此是一个闭包函数,于是看定义的view

①实例化了一个类对象,这里的cls是指UserView类

self = cls(**initkwargs)

②返回self.dispatch,即UserView中的dispatch方法,显然在UserView中没有定义该方法,因此仍然去父类View中寻找

return self.dispatch(request, *args, **kwargs)

③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)

第一步是判断当前reques.method的小写是否在http_method_names中

http_method_names

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

第二步使用getattr反射出当前实例化对象UserView中与request.method对应的方法名称

即UserView.get,UserView.post,UserView.delete等

第三步返回handler(request, *args, **kwargs),即执行UserView.get(request, *args, **kwargs),UserView.post(request, *args, **kwargs)等

④as.view()本质

path('user/', views.UserView.as_view()),        # CBV

 因此views.UserView.as_view()的本质即根据request.method执行在UserView中定义的不同方法,如get,post,delete等

五、总结

了解as.view()的本质后,即可发现FBV和CBV的表面代码虽有不同,但其本质仍是一样,都是通过request.method的不同执行所相对应的代码块,只不过CBV的判断是由其继承的父类View中定义的as_view方法所实现,而FBV则是在自身定义的函数中实现的判断

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Hemameba

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值