基于类的视图简介

使用基于类的视图

本质上,基于类的视图允许您使用不同的类实例方法响应不同的HTTP请求方法,而不是在单个视图函数中通过 if 逻辑来判断使用不同的代码来处理。

在视图函数中处理HTTP请求:

from django.http import HttpResponse

def my_view(request):
    if request.method == 'GET':
        # <view logic>
        return HttpResponse('result')
View Code

 

在基于类的视图中:

from django.http import HttpResponse
from django.views import View

class MyView(View):
    def get(self, request):
        # <view logic>
        return HttpResponse('result')
View Code

 

因为Django的URL解析器希望将请求和相关参数发送给一个可调用的函数,而不是一个类,所以基于类的视图有一个as_view()类方法,它返回一个函数,当一个匹配相关模式的URL的请求到达时,可以调用这个函数。

函数创建类的实例并调用其 dispatch() 方法。 dispatch查看请求以确定它是否是GET、POST等,如果定义了匹配的方法,则将请求转发给匹配的方法,如果没有,则提出HttpResponseNotAllowed:

# urls.py
from django.urls import path
from myapp.views import MyView

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

 

虽然很小的基于类的视图不需要任何类属性来执行其工作,但是类属性在许多基于类的设计中非常有用,并且有两种方法来配置或设置类属性。

第一种是标准的Python方法,它对子类中的属性和方法进行子类化和重写。如果你的父类有这样的属性问候语

from django.http import HttpResponse
from django.views import View

class GreetingView(View):
    greeting = "Good Day"

    def get(self, request):
        return HttpResponse(self.greeting)
View Code

在子类里可以重写它:

class MorningGreetingView(GreetingView):
    greeting = "Morning to ya"

 

另一个选选择是将类属性配置为URLconf中as_view()调用的关键字参数:

urlpatterns = [
    path('about/', GreetingView.as_view(greeting="G'day")),
]

 

使用基于类的视图处理表单

在基于函数的视图中处理表单:

from django.http import HttpResponseRedirect
from django.shortcuts import render

from .forms import MyForm

def myview(request):
    if request.method == "POST":
        form = MyForm(request.POST)
        if form.is_valid():
            # <process form cleaned data>
            return HttpResponseRedirect('/success/')
    else:
        form = MyForm(initial={'key': 'value'})

    return render(request, 'form_template.html', {'form': form})
View Code

 

在基于类的视图中处理表单:

from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.views import View

from .forms import MyForm

class MyFormView(View):
    form_class = MyForm
    initial = {'key': 'value'}
    template_name = 'form_template.html'

    def get(self, request, *args, **kwargs):
        form = self.form_class(initial=self.initial)
        return render(request, self.template_name, {'form': form})

    def post(self, request, *args, **kwargs):
        form = self.form_class(request.POST)
        if form.is_valid():
            # <process form cleaned data>
            return HttpResponseRedirect('/success/')

        return render(request, self.template_name, {'form': form})
View Code

 

这是一个非常简单的例子,但是您可以看到,您可以通过覆盖任何类属性(例如form_class,通过URLconf配置),或者子类化和覆盖一个或多个方法(或者两者都覆盖!)来定制这个视图。

 

装饰基于类的视图

在URLconf中装饰

装饰基于类的视图的最简单方法是装饰 as_view()方法的结果。最简单的方法是在URLconf中部署视图:

from django.contrib.auth.decorators import login_required, permission_required
from django.views.generic import TemplateView

from .views import VoteView

urlpatterns = [
    #给视图所有方法加上 login_required 装饰器
    path('about/', login_required(TemplateView.as_view(template_name="secret.html"))),
    path('vote/', permission_required('polls.can_vote')(VoteView.as_view())),
]
View Code

这种方法在每个实例的基础上应用装饰器。如果希望装饰视图的每个实例,则需要采用不同的方法。

 

装饰class

为了装饰以类为基础的视图的每个实例,您需要装饰类定义本身。要做到这一点,您将装饰器应用于类的dispatch()方法。

类上的方法与独立函数并不完全相同,因此您不能仅对方法应用函数修饰符—您需要首先将其转换为方法修饰符。method_decorator装饰器将函数装饰器转换为方法装饰器,以便可以在实例方法上使用它。例如:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

class ProtectedView(TemplateView):
    template_name = 'secret.html'
    
    #将函数装饰器 login_required 转换为方法装饰器
    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
        return super().dispatch(*args, **kwargs)
View Code

 

或者,更简洁地说,您可以修饰类,并将要修饰的方法的名称作为关键字参数名传递:

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

 

 

如果您在几个地方使用了一组公共装饰器,那么您可以定义一个装饰器列表或元组,并使用它而不是多次调用method_decorator()。下面两个类是等价的:

decorators = [never_cache, login_required]

@method_decorator(decorators, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

@method_decorator(never_cache, name='dispatch')
@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'
View Code

 

装饰器将按照传递给装饰器的顺序处理请求。在本例中, never_cache() 将在 login_required()之前处理请求。

在本例中, ProtectedView 的每个实例都有登录保护

 

 

 

 

学习自用,欢迎大神评论、指正
详情见Django文档:

https://docs.djangoproject.com/zh-hans/2.1/topics/class-based-views/intro/

posted @ 2019-01-26 21:45  Crazy丶土豆  阅读(243)  评论(0编辑  收藏  举报