django類視圖淺析

在Django1.3以前,通用視圖是以函數的方式來實現的。基於函數的實現已經不 建議使用,建議使用這裏介紹的基於類的實現方式。 html

基於類的通用視圖(以及任何繼承了Django提供的基礎類的基於類的視圖)都可以如下面兩種方式被配置:子類化,或者直接經過URLconf來傳遞參數。 web

簡單使用

當你子類化一個類視圖時,你能夠重寫一些屬性(好比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 這個類方法來替代類自己,這是類視圖的入口點: django

# 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 方法中: app

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主要有幾類: url

  1. View(視圖基礎類) spa

  2. SingleObjectMixin(單對象類) 設計

  3. MultipleObjectMixin(多對象類) code

  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

相關文章
相關標籤/搜索