基于类的视图简介
使用基于类的视图
本质上,基于类的视图允许您使用不同的类实例方法响应不同的HTTP请求方法,而不是在单个视图函数中通过 if 逻辑来判断使用不同的代码来处理。
在视图函数中处理HTTP请求:
from django.http import HttpResponse def my_view(request): if request.method == 'GET': # <view logic> return HttpResponse('result')
在基于类的视图中:
from django.http import HttpResponse from django.views import View class MyView(View): def get(self, request): # <view logic> return HttpResponse('result')
因为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)
在子类里可以重写它:
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})
在基于类的视图中处理表单:
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})
这是一个非常简单的例子,但是您可以看到,您可以通过覆盖任何类属性(例如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())), ]
这种方法在每个实例的基础上应用装饰器。如果希望装饰视图的每个实例,则需要采用不同的方法。
装饰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)
或者,更简洁地说,您可以修饰类,并将要修饰的方法的名称作为关键字参数名传递:
@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'
装饰器将按照传递给装饰器的顺序处理请求。在本例中, never_cache()
将在 login_required()
之前处理请求。
在本例中, ProtectedView
的每个实例都有登录保护
学习自用,欢迎大神评论、指正
详情见Django文档:
https://docs.djangoproject.com/zh-hans/2.1/topics/class-based-views/intro/