Django's Class-based Views(基于类的Django视图)

xiaoxiao2021-02-28  13

Introduction to class-based views

Class-based views provide an alternative way to implement views as Python objects instead of functions. They do not replace function-based views, but have certain differences and advantages when compared to function-based views: Organization of code related to specific HTTP methods (GET, POST, etc.) can be addressed by separate methods instead of conditional branching. Object oriented techniques such as mixins (multiple inheritance) can be used to factor code into reusable components.

The relationship and history of generic views, class-based views, and class-based generic views

In the beginning there was only the view function contract, Django passed your function an HttpRequest and expected back an HttpResponse. This was the extent of what Django provided. Early on it was recognized that there were common idioms and patterns found in view development. Function-based generic views were introduced to abstract these patterns and ease view development for the common cases. The problem with function-based generic views is that while they covered the simple cases well, there was no way to extend or customize them beyond some simple configuration options, limiting their usefulness in many real-world applications. Class-based generic views were created with the same objective as function-based generic views, to make view development easier. However, the way the solution is implemented, through the use of mixins, provides a toolkit that results in class-based generic views being more extensible and flexible than their function-based counterparts. If you have tried function based generic views in the past and found them lacking, you should not think of class-based generic views as simply a class-based equivalent, but rather as a fresh approach to solving the original problems that generic views were meant to solve. The toolkit of base classes and mixins that Django uses to build class-based generic views are built for maximum flexibility, and as such have many hooks in the form of default method implementations and attributes that you are unlikely to be concerned with in the simplest use cases. For example, instead of limiting you to a class-based attribute for form_class, the implementation uses a get_form method, which calls a get_form_class method, which in its default implementation just returns the form_class attribute of the class. This gives you several options for specifying what form to use, from a simple attribute, to a fully dynamic, callable hook. These options seem to add hollow complexity for simple situations, but without them, more advanced designs would be limited.


At its core, a class-based view allows you to respond to different HTTP request methods with different class instance methods, instead of with conditionally branching code inside a single view function.(作为核心功能,一个基于类的试图允许我们使用一个类的不同实例方法去应答不同的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')

Because Django’s URL resolver expects to send the request and associated arguments to a callable function, not a class, class-based views have an as_view() class method which returns a function that can be called when a request arrives for a URL matching the associated pattern. The function creates an instance of the class and calls its dispatch() method. dispatch looks at the request to determine whether it is a GET, POST, etc, and relays the request to a matching method if one is defined, or raises HttpResponseNotAllowed if not:(因为Django的URL解析器期望发送一个带有相关参数的请求给可调用函数而不是一个类,所以基于累的视图有一个as_view()类方法,这个方法返回一个能够在请求到达URL完成匹配的时候可供调用的函数,这个函数创建一个当前类的实例并且调用他的dispatch()方法,dispat检查请求然后决定执行GET还是POST等请求,然后将请求转发到一个匹配的已定义方法上,或者自举一个HttpResponseNotAllowed 异常)

# from django.conf.urls import url from myapp.views import MyView#从基于类的视图中导入视图类 urlpatterns = [ url(r'^about/$', MyView.as_view()), ]


from django.http import HttpResponse from django.views import View class GreetingView(View): greeting = "Good Day" def get(self, request): return HttpResponse(self.greeting)

You can override that in a subclass:(下为子类的继承与重写)

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

Another option is to configure class attributes as keyword arguments to the as_view() call in the URLconf:(另外一个选项是配置类的属性作为as_view()的关键参数,然后在URLconf中调用)

urlpatterns = [ url(r'^about/$', GreetingView.as_view(greeting="G'day")), ]

Handling forms with class-based views(使用基于类的视图处理表单)


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

A similar class-based view might look like:(类似的基于类的处理视图是这样的)

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

Decorating class-based views(装饰基于类的视图)

Decorating in URLconf(在URLconf中装饰)

from django.contrib.auth.decorators import login_required, permission_required from django.views.generic import TemplateView from .views import VoteView urlpatterns = [ url(r'^about/$', login_required(TemplateView.as_view(template_name="secret.html"))), url(r'^vote/$', permission_required('polls.can_vote')(VoteView.as_view())), ]

Decorating the class(装饰类)

To decorate every instance of a class-based view, you need to decorate the class definition itself. To do this you apply the decorator to the dispatch() method of the class.(为了装饰每一个基于类的试图实例,需要装饰类自己的定义,将装饰器应用到当前类的dispatch() 方法上去)

A method on a class isn’t quite the same as a standalone function, so you can’t just apply a function decorator to the method – you need to transform it into a method decorator first. The method_decorator decorator transforms a function decorator into a method decorator so that it can be used on an instance method. For example:(累的方法和独立的函数不太一样,所以我们不能直接将函数装饰器应用到类的属性上去,我们需要将其先转换为方法装饰器。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' @method_decorator(login_required) def dispatch(self, *args, **kwargs): return super(ProtectedView, self).dispatch(*args, **kwargs)

Or, more succinctly, you can decorate the class instead and pass the name of the method to be decorated as the keyword argument name:(更简洁的写法,我们可以直接装饰类然后将方法的名称作为关键参数名称传递给装饰器)

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

If you have a set of common decorators used in several places, you can define a list or tuple of decorators and use this instead of invoking method_decorator() multiple times. These two classes are equivalent:(如果有很多公用的装饰器会在很多地方用到,那么我们可以定义一个列表或者元组然后作为参数传递进去)

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'

The decorators will process a request in the order they are passed to the decorator. In the example, never_cache() will process the request before login_required().(装饰器将会根据传递的顺序来执行请求,上例中never_cache() 将会在login_required()之前执行)


Outputting csv(Comma Separated Values) with Django

Outputting PDFs with Django