django类视图浅析

来源:互联网 发布:淘宝商品包装怎么设置 编辑:程序博客网 时间:2024/05/22 16:44

在Django1.3之前,通用视图是以函数的方式来实现的。基于函数的实现已经不 建议使用,建议使用这里介绍的基于类的实现方式。

基于类的通用视图(以及任何继承了Django提供的基础类的基于类的视图)都能够以下面两种方式被配置:子类化,或者直接通过URLconf来传递参数。

简单使用

当你子类化一个类视图时,你可以重写一些属性(比如template_name)或者 一些方法(比如 get_context_data)在你的子类中来提供一些新的值或者方 法。考虑一下,比如,一个仅仅需要展示一个模板的视图,about.html。Django有一个通用视图来完成这个功能 - TemplateView - 因此你可以子类化它,然后重写模板的名称:

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

这时,你只需要添加这个新的视图到你的URLconf配置中。因为类视图本身是一个类,我 们把URL指向 as_view 这个类方法来替代类本身,这是类视图的入口点:

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

作为一个选择,如果你仅仅修改类视图中少量简单的属性,你可以直接传递新的属性 到类本身调用 as_view 方法中:

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

一个类似的重写模式可以用在 RedirectView 的 url 属性上,这是另外一个简单的通用视图。

Minin

如果要深入理解class-based view, 那首先就要了解什么是Mixin! Django把基本的http请求和响应抽象出来, 封装成各自的类, 在使用过程中只需把各个基类聚合到一起使用, 并按照自己的要求重写自己需要的方法就可以了, 那么就把这些基类叫Mixin吧. 在Django中比较基础的Mixin主要有几类:

  1. View(视图基础类)

  2. SingleObjectMixin(单对象类)

  3. MultipleObjectMixin(多对象类)

  4. TemplateResponseMixin(模板响应类)

  5. FormMixin(表单类)

  6. YearMixin, MonthMixin, DayMixin, WeekMixin, DateMixin(几个基于时间关系的类)

其他的所有内置class-based view都是把以上几个基础类组合, 重写方法以达到预期的结果. 比如DetailView这个类就组合了SingleObjectTemplateResponseMixin和BaseDetailView.

对象的通用视图

TemplateView确实很有用,但是你可能需要把数据库中的内容查询展示出来,没关系,Django同样提供了大把内置的通用视图。下面看一个简单例子:

# 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()

为了给所有的Publisher建立一个列表页,我们将按照这样的方式来配置URLconf:

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,template_name=’publisher_list.html‘,    )),)

下面是简单的模板实例:

{% extends "base.html" %}{% block content %}    <h2>Publishers</h2>    <ul>        {% for publisher in object_list %}            <li>{{ publisher.name }}</li>        {% endfor %}    </ul>{% endblock %}

扩展通用视图

使用通用视图可以极大的提高开发速度。然而,在大多时候我们会发现通用视图无法满足需求。为此,我们可以对通用视图进行扩展来增加自己的功能。扩展通用视图的方法是子类化它们,并且重写它们的属性或者方法。

编写”友好的”模板

默认情况下,通用视图将所有相关Model的查询到的对象放到object_list变量中,这虽然能正常工作,但是对模板设计者不友好。

通用视图中的这个属性 : context_object_name指定上下文(context)变量要使用的名字。在这个例子中我们在URLconf中重写了它,因为这只是简单的修改:

urlpatterns = patterns('',    (r'^publishers/$', ListView.as_view(        model=Publisher,        template_name=”publisher_list.html“,        context_object_name="publisher_list",    )),)

我们应该使用context_object_name来指定上下文(context)变量。

添加额外的上下文

我们可能需要一些通用视图没有提供的额外信息,我们可以子类化DetailView然后提供你自己的 get_context_data方法的实现。

DetailView 中默认的实现只是简单的 给模板添加了要展示的对象,但是你这可以这么重写来展示更多信息:

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参数指定了视图(view)在哪个数据库模型之上进行操作,但是这个太不灵活了,我们可以使用 queryset参数来指定一个对象列表:

from django.views.generic import DetailViewfrom books.models import Publisher, Bookclass PublisherDetailView(DetailView):    context_object_name = "publisher"    queryset = Publisher.objects.all()

指明model = Publisher 等价于快速声明的queryset = Publisher.objects.all() 。然而,使用 queryset可以定义一个过滤的对象列表:

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中的关键字来过滤对象。ListView 有一个 get_queryset() 方法来供我们重写。
这里,我们有一个URLconf定义了一组供捕获的参数:

from books.views import PublisherBookListViewurlpatterns = patterns('',    (r'^books/(\w+)/$', PublisherBookListView.as_view()),)

下一个,我们定义了 PublisherBookListView 视图:

from django.shortcuts import get_object_or_404from django.views.generic import ListViewfrom books.models import Book, Publisherclass PublisherBookListView(ListView):    context_object_name = "book_list"    template_name = "books/books_by_publisher.html"    def get_queryset(self):        publisher = get_object_or_404(Publisher, name__iexact=self.args[0])        return Book.objects.filter(publisher=publisher)

参考资料

http://django-14-tkliuxing.readthedocs.org/en/latest/topics/class-based-views.html
http://simple-is-better.com/news/643
http://simple-is-better.com/news/644

0 0
原创粉丝点击