django类视图浅析
django类视图浅析
人间四月 发表于2年前
django类视图浅析
  • 发表于 2年前
  • 阅读 14
  • 收藏 0
  • 点赞 1
  • 评论 0

腾讯云 技术升级10大核心产品年终让利>>>   

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

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

简单使用

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

# some_app/views.py
from django.views.generic import TemplateView
class AboutView(TemplateView):
    template_name = "about.html"

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

# urls.py
from django.conf.urls import patterns, url, include
from some_app.views import AboutView
urlpatterns = patterns('',
    (r'^about/', AboutView.as_view()),)

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

from django.conf.urls import patterns, url, include
from django.views.generic import TemplateView
urlpatterns = 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.py
from django.db import models
class 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, include
from django.views.generic import ListView
from books.models import Publisher
urlpatterns = 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 DetailView
from books.models import Publisher, Book
class 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 DetailView
from books.models import Publisher, Book
class PublisherDetailView(DetailView):
    context_object_name = "publisher"
    queryset = Publisher.objects.all()

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

from django.views.generic import ListView
from books.models import Book
class 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 PublisherBookListView
urlpatterns = patterns('',
    (r'^books/(\w+)/$', PublisherBookListView.as_view()),)

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

from django.shortcuts import get_object_or_404
from django.views.generic import ListView
from books.models import Book, Publisher
class 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

共有 人打赏支持
粉丝 3
博文 70
码字总数 30455
×
人间四月
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
* 金额(元)
¥1 ¥5 ¥10 ¥20 其他金额
打赏人
留言
* 支付类型
微信扫码支付
打赏金额:
已支付成功
打赏金额: