2、View源码解析和drf的View

文章详细比较了Django和DjangoRestFramework(DRF)中的函数基类视图(FBV)与类基类视图(CBV)的实现,着重讲解了as_view()函数的作用以及在处理HTTP请求时的区别。
摘要由CSDN通过智能技术生成

目录

FBV和CBV表象

as_view()做了什么?

drf的View

FBV和CBV表象

view.py

# FBV
def index(request):
    if request.method == "GET":
        return JsonResponse({'status': True, 'message': "GET"})
    elif request.method == "POST":
        return JsonResponse({'status': True, 'message': "POST"})


# CBV
class IndexView(View):

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

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

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

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

url.py

urlpatterns = [
    # path('admin/', admin.site.urls),
    path('index/', index),
    path('IndexView/', IndexView.as_view()),
]

发现FBV通过ifrequest.method来区分请求方式而CBV通过方法来区分。

url中他们的调用方式不同,FBV直接传递函数名,CBV还需要调用类视图下的as_view()方法才可以。

as_view()做了什么?

IndexView.as_view()既然是类方法,那么IndexView中有 as_view方法么?没有,那么我们来看看父类View中。

View中有 as_view方法,那么我们截取其中有用的代码来看看他做了什么?

class View:
    http_method_names = [
        "get",
        "post",
        "put",
        "patch",
        "delete",
        "head",
        "options",
        "trace",
    ]
    
    @classonlymethod
    def as_view(cls, **initkwargs):
        # view函数
        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__
                )
            # 调用 dispath并返回
            return self.dispatch(request, *args, **kwargs)

        return view
        
    def setup(self, request, *args, **kwargs):
        """Initialize attributes shared by all view methods."""
        # 如果你的方法中有 get 且没有 head那么 head = get
        if hasattr(self, "get") and not hasattr(self, "head"):
            self.head = self.get
        self.request = request
        self.args = args
        self.kwargs = kwargs

    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.
        # 将方法转成小写 http_method_names就是类开头定义的列表
        if request.method.lower() in self.http_method_names:
            # 假设 request.method.lower() = get 那么这句话就是获取你的get方法
            handler = getattr(
                self, request.method.lower(), self.http_method_not_allowed
            )
        else:
            handler = self.http_method_not_allowed
        # 调用并返回你所调用的方法
        return handler(request, *args, **kwargs)

这样就很清晰能看出,as_view()返回了一个view函数,这样就在urlpath方法中和FBV相同了。被调用后通过dispath()调用了你所定义的方法,get或者post或者其他方法。

drf的View

view.py

from rest_framework.response import Response
from rest_framework.views import APIView


class RFWView(APIView):
    def get(self, request):
        return Response("drf view get")

url.py

urlpatterns = [
    path('RFWView/', RFWView.as_view()),
]

RFWView继承了APIView那么我们来看看DRFAPIViewas_view()是如何写的(摘取重要代码)

class APIView(View):
    def as_view(cls, **initkwargs):
        ...
        
        # 调用父类,调用的就是django原生的as_view
        view = super().as_view(**initkwargs)
        view.cls = cls
        view.initkwargs = initkwargs
        
        # 避免csrf验证
        return csrf_exempt(view)

    def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        # 赋值参数
        self.args = args
        self.kwargs = kwargs

        # 现在的request 还是django原生request
        request = self.initialize_request(request, *args, **kwargs)
        # 在这 request 变成了 drf 的 request

        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            self.initial(request, *args, **kwargs)

            # 实现了django原生dispatch功能
            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
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值