Django中的as_view方法源码分析

本文深入剖析Django框架中的类视图实现原理,重点介绍了as_view方法如何将类转换成视图函数,并通过dispatch方法根据不同的HTTP请求类型执行相应的处理逻辑。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

django的类视图拥有自动查找指定方法的功能,通过调用as_views()方法实现。

在探讨这个问题之前,先引入一段代码举个例子方便理解:

  • 一般请求的判断方法:
def View(request,*args,**kwargs):
	if request.method.lower() == 'get':
		do_something()
	if request.method.lower() == 'post':
		do_something()
  • 编写自定义的视图类,前提必须要继承基类View,然后使用View.as_view()代替判断:
class ClassName(View):
    '''
    继承View自动判断请求方法
    '''
    def post():
        pass

    def get():
        pass

    def other():
        pass

#调用方法
url(url, ClassName.as_view(), name)

设计思想:把视图函数的逻辑定义到类的方法里面去,然后在函数中实例化这个类,通过调用类的方法实现函数逻辑。而把逻辑定义在类中的一个好处就是可以通过继承复用这些方法。


那么问题来了,as_view()这个方法是如何执行对应自定义的get或者post方法呢?

as_view

如果你曾经使用过类视图,那么最熟悉的应该就是这个方法了。要想让类视图生效,必须在 urls.py 的 URL 模式(Pattern)里做类似如下的配置:

# urls.py
from .views import IndexView  # 导入自定义的视图类

urlpatterns = [
	url(r^'^$',IndexView.as_view(),name='index')
]

Django 使用如上的方式配置 URL 到对应视图函数的路由映射。注意到 url() 函数前两个位置参数需要传递的值,第一个是需要捕获的 url 的正则模式,第二个参数则是一个可调用的对象(即视图函数)。如果我们通过 def 定义视图函数,那么传入的这个可调用对象就是这个函数本身;而如果我们定义的是类视图,则必须调用类视图的 as_view 方法返回一个根据这个类生成的可调用对象。类视图所有的魔法就在这个函数里了,来看看 Django 究竟是如何神奇地把一个类转为一个函数的。

   @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.request = request
            self.args = args
            self.kwargs = kwargs
            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

as_view 方法被调用时允许传递一些关键字参数,不过需要做一个点点检查,第一防止你传入诸如 get、post 这样的关键字参数把类本身的 get、post 方法覆盖了;第二是防止你传入未定义为类属性的参数。最开始的 for 循环就是做这个事。

接下来在 as_view 方法中又定义了一个 view 方法,这个方法相信如果你经常写视图函数的话应该非常眼熟,这就是视图函数的标准定义:接收一个 HttpRequest 对象,以及从 url 捕获的非命名组和命名组参数。只不过在 view 这个视图函数里还多做了一点事,它首先实例化了一个类视图对象,然后把函数的参数设置为了这个类视图实例的属性,接着便调用了实例的 dispatch 方法返回视图函数被要求返回的 HttpResponse 对象(注意 dispatch 方法会根据 HTTP 请求方法的不同去调用对应的处理方法)。接着把类中的一些文档字符串和函数名等更新到定义的 view 函数中,然后 as_view 方法返回这个 view 函数。

调用顺序: as_view --> view --> dispatch
  • 可以看出as_view实际上是一个闭包,他的作用就是做一些检验工作,再返回view方法
  • view方法的作用是给请求对象补充三个参数,并调用dispatch方法处理
  • dispatch方法查找到指定的请求方法,并执行相应代码块
可以得出结论:as_view方法实际上最后就是要调用dispatch方法

所以回过头来再看一下我们的 url 模式定义:

urlpatterns = [
	url(r^'^$',IndexView.as_view(),name='index')
]

views.IndexView.as_view() 调用后返回的就是一个在 IndexView 里通过 def 定义的视图函数 view(注意所有类视图都继承自 View 基类),是不是和你直接在这里放一个视图函数是一样的?

附加一张图片加深印象:

在这里插入图片描述

总结

现在我们已经明白了类视图的基本结构,其主要功能就是根据 HTTP 请求方法的不同做出相应处理,具体的实现为 dispatch 方法。类视图的核心思想就是把视图函数的逻辑定义到类的方法里面去,然后在函数中实例化这个类,通过调用类的方法实现函数逻辑。

参考:源码分析文档

### Django框架源码获取与结构分析 Django 是一个开源的 Web 框架,其源代码托管在 GitHub 上,开发者可以通过访问 [Django GitHub 仓库](https://github.com/django/django) 获取完整的源代码。Django 的源码结构清晰,主要由以下几个核心模块组成: - **django/db**:包含数据库相关的模块,如 ORM、查询构建器、迁移系统等。 - **django/http**:处理 HTTP 请求和响应,包括 `HttpRequest` 和 `HttpResponse` 类。 - **django/core**:核心功能模块,如模板引擎、中间件支持、缓存系统等。 - **django/urls**:URL 分发机制,支持正则表达式匹配、路径转换器等路由配置方式。 - **django/contrib**:官方提供的扩展模块,如 admin、auth、sessions 等。 Django 的源码采用模块化设计,开发者可以深入研究其内部实现机制,例如: - **ORM 实现**:Django 的 ORM 通过 `QuerySet` 类实现数据库操作的链式调用,支持过滤、排序、聚合等功能。其底层通过 `django.db.models.sql` 模块将 Python 表达式转换为 SQL 查询语句。 - **中间件机制**:Django 的请求处理流程通过中间件链实现,开发者可以在 `MIDDLEWARE` 设置中配置中间件类,每个中间件类可以定义 `process_request` 和 `process_response` 方法来处理请求和响应。 - **模板系统**:Django 的模板引擎支持变量、标签、过滤器等语法,其解析过程由 `django.template` 模块完成,支持模板继承和自定义标签。 在开发过程中,开发者可以使用 `pip install -e .` 命令将 Django 源码安装为可编辑模式,便于调试和修改源码内容。 ### Django REST Framework 源码结构 Django REST Framework(DRF)是 Django 的扩展库,用于构建 RESTful API。其源码托管在 [DRF GitHub 仓库](https://github.com/encode/django-rest-framework)。DRF 的主要模块包括: - **rest_framework/views.py**:定义了 `APIView` 类,继承自 Django 的 `View` 类,增强了对请求方法的封装,支持请求和响应的统一处理。 - **rest_framework/generics.py**:提供通用视图类,如 `ListAPIView`、`RetrieveAPIView` 等,简化了常见 API 的开发。 - **rest_framework/viewsets.py**:定义了 `ViewSet` 和 `GenericViewSet` 类,支持将多个视图逻辑封装在一个类中,并与路由器(`DefaultRouter`)结合使用。 - **rest_framework/routers.py**:提供路由器机制,如 `DefaultRouter`,用于自动生成 URL 配置,简化路由管理。 DRF 的版本控制功能通过 `rest_framework.versioning` 模块实现,支持多种版本控制策略,如基于 URL 路径的 `URLPathVersioning` 和基于请求头的 `AcceptHeaderVersioning`。开发者可以通过配置 `REST_FRAMEWORK` 设置启用版本控制功能。 ### 示例:基于 DRF 的视图与路由配置 ```python # views.py from rest_framework.views import APIView from rest_framework.response import Response class LoginView(APIView): def get(self, request, *args, **kwargs): return Response({"message": "Login successful"}) ``` ```python # urls.py from django.urls import path from . import views urlpatterns = [ path('dj2/', views.LoginView.as_view()), path('<str:version>/dj2/', views.LoginView.as_view(), name="hh"), ] ``` 上述代码展示了基于 DRF 的视图类 `LoginView`,该类继承自 `APIView`,并重写了 `get` 方法以返回 JSON 响应。URL 路由通过 `path` 函数配置,支持路径参数 `<str:version>`,并绑定到视图类的 `as_view()` 方法。 ### 示例:基于路由器的视图集配置 ```python # views.py from rest_framework import viewsets from .models import Result from .serializers import ResultSerializer class ResultViewSet(viewsets.ModelViewSet): queryset = Result.objects.all() serializer_class = ResultSerializer def history_result(self, request): # 自定义方法处理历史结果 return Response({"message": "History result fetched"}) ``` ```python # urls.py from django.urls import path from rest_framework.routers import DefaultRouter from . import views router = DefaultRouter() router.register(r'result/all', views.ResultViewSet) urlpatterns = [ path(r'result/all/user', views.ResultViewSet.as_view({'post': 'history_result'})), ] urlpatterns += router.urls ``` 上述代码展示了基于 DRF 的 `ModelViewSet` 实现的 `ResultViewSet`,该类支持标准的 CRUD 操作。开发者可以通过 `router.register` 方法将其注册到 URL 路由中,同时也可以通过 `as_view` 方法绑定自定义动作 `history_result`。 ###
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值