首页 > 代码库 > 基于类的通用视图

基于类的通用视图

基于类的通用视图

前面我们说过了django的通用视图,不知道django通用视图的去看我前面的随笔,谢谢

django的通用视图帮我们省略了很多代码,但有时候django的通用视图并不能满足我们全部的需求,例如像重定义一些属性和方法的时候,或者我们想换种写法的时候,因此,django提供了基于类的通用视图,通过子类或者在url中传参的方法来配置我们的基于类的通用视图

通用视图和基于类的通用视图是两种不一样的写法,前面我们介绍的通用视图,所有的代码集中于url的配置文件中,而基于类的通用视图主要集中于配置“继承然后覆盖父类方法和属性”方面

简单用法

考虑你仅仅想要显示一个模板about.html,django提供了一个通用视图去做这件事,我们只需要继承它,然后覆盖覆盖模板名称即可,其实TemplateView类对应的是direct_to_template

# some_app/views.pyfrom django.views.generic import TemplateViewclass AboutView(TemplateView):    template_name = "about.html"

然后再url配置文件中直接调用相应的方法即可

# urls.pyfrom django.conf.urls import patterns, url, includefrom some_app.views import AboutViewurlpatterns = patterns(‘‘,    (r^about/, AboutView.as_view()),)

或者我们可以直接在url中通过传参的方法达到修改属性的目的

from django.conf.urls import patterns, url, includefrom django.views.generic import TemplateViewurlpatterns = patterns(‘‘,    (r^about/, TemplateView.as_view(template_name="about.html")),)

对象的通用视图

首先这是我们可能会用到的model

# models.pyfrom django.db import modelsclass Publisher(models.Model):    name = models.CharField(max_length=30)    address = models.CharField(max_length=50)    city = models.CharField(max_length=60)    state_province = models.CharField(max_length=30)    country = models.CharField(max_length=50)    website = models.URLField()    class Meta:        ordering = ["-name"]    def __unicode__(self):        return self.nameclass Book(models.Model):    title = models.CharField(max_length=100)    authors = models.ManyToManyField(Author)    publisher = models.ForeignKey(Publisher)    publication_date = models.DateField()

为了生成一个所有出版商的页面,我们可以在url中这样写

from django.conf.urls import patterns, url, includefrom django.views.generic import ListViewfrom books.models import Publisherurlpatterns = patterns(‘‘,    (r^publishers/$, ListView.as_view(        model=Publisher,    )),)

在这里我们没有指定模板名,那么会使用ListView默认的模板名默认模板<app_label>/<model_name>_list.html ,这里可能是/books/publisher_list.html

拓展通用视图

制作友好的模板上下文名称

如果你在和模型打交道,使用下面的配置可以使你自己定义一个更好用(django内部有规则生成一个)的模板上下文名称,这可能使得和你合作的模板设计师对你有好感,因为有时候django自动生成的模板上下文名称很冗长

urlpatterns = patterns(‘‘,    (r^publishers/$, ListView.as_view(        model=Publisher,        context_object_name="publisher_list",    )),)

增加额外的上下文内容

有时候默认的通用视图提供的上下文内容不能满足你的需求,比如一个返回所有出版商的列表的页面,上面可能一点和书籍的信息都没有,这时候你可以通过继承相应的父类,覆盖父类的方法为子类添加额外的内容

from django.views.generic import DetailViewfrom books.models import Publisher, Bookclass PublisherDetailView(DetailView):    context_object_name = "publisher"    model = Publisher    def get_context_data(self, **kwargs):        # Call the base implementation first to get a context        context = super(PublisherDetailView, self).get_context_data(**kwargs)        # Add in a QuerySet of all the books        context[‘book_list‘] = Book.objects.all()        return context

对象的查看子集

注意到的一点,model属性和queryset属性,model=Publisher和queryset=Publisher.objects.all()基本是一致的,基于这一点,我们可以通过制定queryset的方法以至于不必每次都收返回一个模型的全集,可以每次只返回一个子集,当然,我们也可以在url中达到这个目标

urlpatterns = patterns(‘‘,    (r^publishers/$, ListView.as_view(        queryset=Publisher.objects.all(),        context_object_name="publisher_list",    )),    (r^books/$, ListView.as_view(        queryset=Book.objects.order_by("-publication_date"),        context_object_name="book_list",    )),)
from django.views.generic import ListViewfrom books.models import Bookclass AcmeBookListView(ListView):    context_object_name = "book_list"    queryset = Book.objects.filter(publisher__name="Acme Publishing")    template_name = "books/acme_list.html"

动态筛选

还有一个常用的需求是根据url中的参数去查询数据库,之前我们可以把出版商的名字硬编码在url中,但如果我们要写一个能够根据任意给定的出版商,返回该出版商的所有书籍的视图呢?我们可以覆盖get_queryset()这个方法

    def get_queryset(self):        publisher = get_object_or_404(Publisher, name__iexact=self.args[0])        return Book.objects.filter(publisher=publisher)

执行额外的工作

假如Author这个模型有一个last_accessed的date类型属性,我们要求每次访问的时候都更新这个属性,显然,django的通用视图是根本不知道Author有这样的一个属性的,所以我们必须重写某个方法以增加这个行为,在这里是get_object()方法

import datetimefrom books.models import Authorfrom django.views.generic import DetailViewfrom django.shortcuts import get_object_or_404class AuthorDetailView(DetailView):    queryset = Author.objects.all()    def get_object(self):        # Call the superclass        object = super(AuthorDetailView, self).get_object()        # Record the last accessed date        object.last_accessed = datetime.datetime.now()        object.save()        # Return the object        return object

装饰基于类的视图

在url中装饰

from django.contrib.auth.decorators import login_required, permission_requiredfrom django.views.generic import TemplateViewfrom .views import VoteViewurlpatterns = patterns(‘‘,    (r^about/, login_required(TemplateView.as_view(template_name="secret.html"))),    (r^vote/, permission_required(polls.can_vote)(VoteView.as_view())),)

在类中装饰

from django.contrib.auth.decorators import login_requiredfrom django.utils.decorators import method_decoratorfrom django.views.generic import TemplateViewclass ProtectedView(TemplateView):    template_name = secret.html    @method_decorator(login_required)    def dispatch(self, *args, **kwargs):        return super(ProtectedView, self).dispatch(*args, **kwargs)

p

基于类的通用视图