首页 > 代码库 > 基于类的通用视图
基于类的通用视图
基于类的通用视图
前面我们说过了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
基于类的通用视图