目前為止我們講到Django怎樣試圖在模型和模板層去除單調(diào)乏味,但是web開(kāi)發(fā)人員也在視圖層感到厭倦
Django的generic views就是開(kāi)發(fā)來(lái)解除這個(gè)痛苦的,它在視圖開(kāi)發(fā)上采用了一些常用的慣例和模式,
并且把視圖開(kāi)發(fā)抽象出來(lái),以致你可以在數(shù)據(jù)之上用不多的代碼迅速的寫(xiě)常見(jiàn)的視圖
事實(shí)上,前面章節(jié)中幾乎每個(gè)視圖例子都可以用generic views重寫(xiě)
Django包含generic views來(lái)做下面的事情:
1,處理常見(jiàn)的簡(jiǎn)單任務(wù):重定向到不同的頁(yè)面和渲染給定的模板
2,顯示列表和一個(gè)單獨(dú)對(duì)象的細(xì)節(jié)頁(yè)面,例如Django文檔首頁(yè)和單獨(dú)的文檔頁(yè)面就是這種形式
(http://www.djangoproject.com/documentation)從第5章開(kāi)始的視圖可以很容易的使用
generic views重寫(xiě),我們下面將做這件事
3,在year/month/day存檔頁(yè)面顯示基于日期的對(duì)象,相關(guān)的細(xì)節(jié)以及最近的頁(yè)面,Django的weblog
(http://www.djangoproject.com/weblog)的year,month和day存檔就是用基于此構(gòu)建的
以及l(fā)jworld.com的新聞存檔等等
4,允許用戶使用授權(quán)或不使用授權(quán)來(lái)創(chuàng)建,編輯,刪除對(duì)象
總的來(lái)說(shuō),這些視圖提供了容易的接口來(lái)處理開(kāi)發(fā)人員遇到的最常見(jiàn)的任務(wù)
使用generic views
所有的這些視圖被用來(lái)在你的URL配置文件里創(chuàng)建配置字典并把這些字典作為第3個(gè)參數(shù)傳遞給一個(gè)給定的模式
例如下面是一個(gè)簡(jiǎn)單的在djangoproject.com上寫(xiě)blog的weblog app的URL配置:
- from django.conf.urls.defaults import *
- from django_website.apps.blog.models import Entry
- info_dict = {
- 'queryset': Entry.objects.all(),
- 'date_field': 'pub_date',
- }
- urlpatterns = patterns('django.views.generic.date_based',
- (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/(?P<slug>[-\w]+)/$', 'object_detail', dict(info_dict, slug_field='slug')),
- (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\w{1,2})/$', 'archive_day', info_dict),
- (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'archive_month', info_dict),
- (r'^(?P<year>\d{4})/$', 'archive_year', info_dict),
- (r'^/?$', 'archive_index', info_dict),
- )
你可以看到,這個(gè)URL配置在info_dict里定義了一些選項(xiàng),'queryset'傳遞一個(gè)QuerySet的對(duì)象給generic view使用(這里的
情況下,傳遞的是所有的Entry對(duì)象),并且告訴generic view哪個(gè)模型正在被使用,對(duì)于每個(gè)generic view剩下的參數(shù)都通過(guò)
URL配置里的命名參數(shù)捕獲得到
這就是Django的weblog的所有視圖代碼!剩下的唯一的事情就是寫(xiě)模板
每個(gè)generic view需要一些關(guān)鍵字參數(shù),記住上面的例子中,參數(shù)可以來(lái)自于URL模式(如month,day,year等等),也可以來(lái)
自于額外的信息字典(如queryset,date_field等等)
大部分generic views需要queryset鍵,它是一個(gè)QuerySet實(shí)例,參考附錄3的數(shù)據(jù)庫(kù)API得到更多關(guān)于QuerySet對(duì)象的信息
大部分視圖也需要一個(gè)可選的extra_context字典,你可以通過(guò)它傳遞任意輔助信息到視圖中去
在extra_context字典中的值可以是方法或者其它對(duì)象,方法在傳遞到模板之前會(huì)計(jì)算出值
"簡(jiǎn)單的" generic views
django.views.generic.simple模塊包含了簡(jiǎn)單的處理一些常見(jiàn)情況的視圖:不需要視圖邏輯時(shí)渲染模板和處理重定向
渲染模板
django.views.generic.simple.direct_to_template渲染一個(gè)給定的模板,并把在URL里捕獲的參數(shù)組成字典作為{{ params }}
模板變量傳遞給它
例子:
給定下面的URL模式:
- urlpatterns = patterns('django.views.generic.simple',
- (r'^foo/$', 'direct_to_template', {'template': 'foo_index.html'}),
- (r'^foo/(?P<id>\d+)/$', 'direct_to_template', {'template': 'foo_detail.html'}),
- )
對(duì)/foo/的請(qǐng)求將渲染foo_index.html模板,對(duì)/foo/15/的請(qǐng)求則渲染foo_detail.html并有一個(gè)context變量{{ params.id }}值為15
必需的參數(shù):
template
使用的模板的完整名
重定向到另一URL
django.views.generic.simple.redirect_to重定向到另一個(gè)URL,給定的URL可能包含字典樣式的string格式,它將插入到URL
如果給定的URL是None,Django將返回一個(gè)HTTP 410(不可用)信息
例子:
下面的例子從/foo/<id>/重定向到/bar/<id>/:
- urlpatterns = patterns('django.views.generic.simple',
- ('^foo/(?p<id>\d+)/$', 'redirect_to', {'url': '/bar/%(id)s/'}),
- )
下面的例子對(duì)/bar/的請(qǐng)求返回一個(gè)410 HTTP錯(cuò)誤:
- urlpatterns = patterns('django.views.generic.simple',
- ('^bar/$', 'redirect_to', {'url': None}),
- )
必需的參數(shù):
url
重定向到的URL地址,它是一個(gè)string,或者None將返回410 HTTP(不可用)應(yīng)答
更復(fù)雜的generic views
盡管簡(jiǎn)單generic views很有用,但Django的generic views真正強(qiáng)大之處來(lái)自于允許你使用很少的代碼構(gòu)建常見(jiàn)的CRUD(增/刪/查
/改)頁(yè)面的更復(fù)雜的視圖
這些視圖分為下列這些不同的類型:
1,List/detail視圖,它提供對(duì)象列表和單獨(dú)對(duì)象細(xì)節(jié)的頁(yè)面(例如地點(diǎn)列表和單獨(dú)的一個(gè)地點(diǎn)的信息頁(yè)面)
2,Date-based視圖,它提供year/month/day樣式的以日期為中心的信息頁(yè)面
3,Create/update/delete視圖,它允許你快速創(chuàng)建增,刪,改對(duì)象的視圖
通用的可選參數(shù)
allow_empty
一個(gè)布爾值,指定沒(méi)有對(duì)象時(shí)是否顯示頁(yè)面,如果它是False并且沒(méi)有對(duì)象,視圖將觸發(fā)404錯(cuò)誤而不是顯示空頁(yè)面,默認(rèn)是False
context_processors
一個(gè)視圖模板的template-context processors列表,參考第10章得到更多template context processors的信息
extra_context
一個(gè)添加到模板context的字典值,它默認(rèn)為空字典,如果字典中的一個(gè)值可以調(diào)用,generic view將在渲染模板前調(diào)用它
mimetype
用來(lái)生成結(jié)果文檔的MIME類型,默認(rèn)為DEFAULT_MIME_TYPE設(shè)置的值
template_loader
當(dāng)載入模板時(shí)使用的模板載入器,默認(rèn)為django.template.loader,參考第10章得到更多關(guān)于模板載入器的信息
template_name
渲染頁(yè)面時(shí)使用的完整的模板名,它可以讓你覆蓋來(lái)自于QuerySet的默認(rèn)模板名
template_object_name
指定在模板context中的模板變量名,默認(rèn)為'object',視圖列表列出不止一個(gè)對(duì)象時(shí)將在此變量值后添加'_list'
列表/細(xì)節(jié)generic views
列表-細(xì)節(jié)generic views(在django.views.generic.list_detail模塊中)處理常見(jiàn)的在一個(gè)視圖里顯示
一個(gè)列表的項(xiàng)目和顯示單獨(dú)的一項(xiàng)的細(xì)節(jié)視圖
我們看看簡(jiǎn)單的第5章和第6章的簡(jiǎn)單的book/author/publisher對(duì)象:
- class Publisher(models.Model):
- name = models.CharField(maxlength=30)
- address = models.CharField(maxlength=50)
- city = models.CharField(maxlength=60)
- state_province = models.CharField(maxlength=30)
- country = models.CharField(maxlength=50)
- website = models.URLField()
- class Author(models.Model):
- salutation = models.CharField(maxlength=10)
- first_name = models.CharField(maxlength=30)
- last_name = models.CharField(maxlength=40)
- email = models.EmailField()
- headshot = models.ImageField()
- class Book(models.ModelField):
- title = models.CharField(maxlength=100)
- authors = models.ManyToManyField(Author)
- publisher = models.ForeignKey(Publisher)
- publication_date = models.DateField()
我們也需要和一個(gè)URL模塊工作,如果你在跟著做,你可以配置bookstore.urls的骨架:
- from django.conf.urls.defaults import *
- from django.views.generic import list_detail, date_based, create_update
- from bookstore.models import Publisher, Author, Book
- urlpatterns = patterns('',
- # We'll add URL patterns here.
- )
我們將用generic views把這些搭建起來(lái)
對(duì)象列表
django.views.generic.list_detail.object_list視圖用來(lái)創(chuàng)建一個(gè)顯示對(duì)象列表的頁(yè)面
例子:
我們可以使用object_list視圖來(lái)顯示一個(gè)簡(jiǎn)單的bookstore中authors的列表
首先,我們需要為generic view創(chuàng)建一個(gè)info字典,把下面的代碼加到bookstore/urls.py文件:
- author_list_info = {
- 'queryset' : Author.objects.all(),
- 'allow_empty': True,
- }
然后,我們需要注冊(cè)這個(gè)視圖到某一個(gè)URL,我們可以通過(guò)在patterns里加入這個(gè)URL配置:
- (r'authors/$', list_detail.object_list, author_list_info)
我們只需為generic view制作一個(gè)模板來(lái)渲染即可,既然我們沒(méi)有提供template_name參數(shù),Django將
猜測(cè)模板的名字,這里將是bookstore/author_list.html,參考下面更多細(xì)節(jié)
必需的參數(shù):
queryset
用來(lái)列表的對(duì)象的QuerySet
可選的參數(shù):
paginate_by
你個(gè)指出每一頁(yè)多少對(duì)象應(yīng)該被顯示的整數(shù),如果這項(xiàng)被給定,視圖將使用paginate_by分頁(yè)
視圖將希望得到一個(gè)包含了從零開(kāi)始索引頁(yè)數(shù)的page查詢字符串參數(shù)(通過(guò)GET),或者一個(gè)在
URL配置里指定的page變量,參看下面的"分頁(yè)的注意點(diǎn)"
另外,這個(gè)視圖可以使用上面描述的任何通用參數(shù):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
模板名:
如果template_name沒(méi)有被指定,視圖將默認(rèn)使用(app_label)/(model_name)_list.html
app標(biāo)簽和模型名字兩者都來(lái)自于queryset參數(shù),app標(biāo)簽是模型定義所在的app的名字,模型名字則是
模型類的名字的小寫(xiě)版本
所以當(dāng)我們把Author.objects.all()作為queryset傳遞時(shí),app標(biāo)簽將是bookstore,模型名則是author
這意味著默認(rèn)的模板將是bookstore/author_list.html
模板context:
除了extra_context,模板的context將包括:
object_list
對(duì)象的列表,這個(gè)變量的名字取決于template_object_name參數(shù),而后者默認(rèn)是'object'
如果template_object_name是'foo',則這個(gè)變量的名字就是foo_list
is_paginated
一個(gè)boolean值,它表示結(jié)果是否分頁(yè)
特別的,當(dāng)可得到的對(duì)象的數(shù)量小于或等于paginate_by時(shí),它的值被設(shè)為False
如果結(jié)果是分頁(yè)的,context將包含以下額外變量
results_per_page
每頁(yè)對(duì)象的數(shù)量(和paginate_by參數(shù)一樣)
has_next
一個(gè)boolean值,它表示是否有下一頁(yè)
has_previous
一個(gè)boolean值,它表示是否有上一頁(yè)
page
當(dāng)前頁(yè)的頁(yè)數(shù),它是一個(gè)整數(shù),從1開(kāi)始
next
下一頁(yè)的頁(yè)數(shù),它是一個(gè)整數(shù),如果沒(méi)有下一頁(yè),它還是一個(gè)整數(shù)并表示理論上的下一頁(yè)頁(yè)數(shù),從1開(kāi)始
previous
上一頁(yè)的頁(yè)數(shù),它是一個(gè)整數(shù),從1開(kāi)始
pages
總頁(yè)數(shù),它是一個(gè)整數(shù)
hits
所有頁(yè)面的對(duì)象的總數(shù),不僅僅是當(dāng)前頁(yè)
分頁(yè)的注意點(diǎn):
如果pagenate_by被指定,Django將對(duì)結(jié)果分頁(yè),你可以通過(guò)下面兩種方式在URL指定頁(yè)數(shù)
1,在URL配置里使用page參數(shù),例如一個(gè)URL配置:
- (r'^objects/page(?P<page>[0-9]+)/$', 'object_list', dict(info_dict))
2,通過(guò)page查詢字符串參數(shù)傳遞頁(yè)數(shù),例如一個(gè)URL:
- /objects/?page=3
兩種方式中page都是從1開(kāi)始而不是從0開(kāi)始,所以第一個(gè)頁(yè)面將表示為頁(yè)面1
細(xì)節(jié)視圖
django.views.generic.list_detail.object_detail提供了一個(gè)單獨(dú)對(duì)象的細(xì)節(jié)視圖
例子:
擴(kuò)展上面的例子,我們可以為給定的author創(chuàng)建一個(gè)細(xì)節(jié)視圖,像下面這樣提供一個(gè)info字典:
- author_detail_info = {
- "queryset" : Author.objects.all(),
- "template_object_name" : "author",
- }
我們可以使用下面的URL模式:
- (r'^authors/(?P<object_id>\d+)/$', list_detail.object_detail, author_detail_info),
渲染bookstore/author_detail.html模板來(lái)顯示一個(gè)給定的author的細(xì)節(jié)
在這個(gè)模板中,Author對(duì)象本身將會(huì)被放置到{{ author }}變量中
必需的參數(shù):
queryset
用來(lái)搜索對(duì)象的QuerySet
或者
object_id
對(duì)象的主鍵域的值
或者
slug
給定對(duì)象的slug值,如果你傳遞這個(gè)域,slug_field參數(shù)也是必需的
可選的參數(shù):
slug_field
對(duì)象中包含slug的域的名字,如果你使用slug參數(shù),則它是必需的,如果你使用object_id參數(shù)則不能要
這個(gè)參數(shù)
template_name_field
對(duì)象中代表使用的模板的名字的域的名字,這可以讓你在數(shù)據(jù)中存儲(chǔ)模板名字
換句話說(shuō),如果你的對(duì)象有一個(gè)'the_template'域并且該域包含一個(gè)字符串'foo.html',你把
template_name_field設(shè)置為the_template,則這個(gè)對(duì)象的generic view將使用模板'foo.html'
這有點(diǎn)思路纏繞的感覺(jué),但是在某些情況下很有用
這個(gè)視圖也可以使用下面的通用參數(shù):
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
模板名:
如果沒(méi)指定template_name和template_name_field,本視圖默認(rèn)使用(app_label)/(model_name)_detail.html
模板context
除了extra_context,模板的context是
object
對(duì)象,這個(gè)變量的名字取決于template_object_name參數(shù),默認(rèn)是'object',如果template_object_name
是'foo',這個(gè)變量的名字就是foo
基于日期的generic views
基于日期的generic views通常用來(lái)為基于日期的資料提供一套"存檔"頁(yè)面,考慮一個(gè)報(bào)紙的year/month/day存檔,或者類似于
本章開(kāi)始描述的Django官方blog的blog
下面這個(gè)例子我們將使用Book對(duì)象并且構(gòu)建一種通過(guò)year,month和day發(fā)表日期來(lái)瀏覽books的方式
注意對(duì)于這些視圖中的每一個(gè)我們都必須告訴Django我們想要查看的日期的域的名字,我們必須提供這個(gè)信息,因?yàn)槟P涂赡?
包含了多個(gè)date或datetime域
到未來(lái)去
默認(rèn)這些視圖忽略具有未來(lái)日期的對(duì)象,這意味著如果你試圖訪問(wèn)一個(gè)未來(lái)的存檔頁(yè)面,即使那一天有對(duì)象發(fā)表,Django也將
自動(dòng)顯示404(找不到頁(yè)面)錯(cuò)誤
這樣的話,你可以發(fā)表具有日期的對(duì)象,它們直到過(guò)了發(fā)表日期才會(huì)顯示給公眾
但是,對(duì)于不同類型的基于日期的對(duì)象而言這可能不合適(例如顯示即將發(fā)生的事件的日程表)
對(duì)于這些視圖,設(shè)置allow_future選項(xiàng)為True即可,用戶就可以訪問(wèn)"未來(lái)"的存檔頁(yè)面
存檔首頁(yè)
django.views.generic.date_based_archive_index視圖提供了一個(gè)通過(guò)日期顯示最近的對(duì)象的頂級(jí)首頁(yè)
例子:
一個(gè)典型的publisher可能想把最近發(fā)表的books設(shè)為語(yǔ)法高亮,我們可以使用archive_index視圖來(lái)做這件事,下面是info dict:
- book_info = {
- "queryset" : Book.objects.all(),
- "date_field" : "publication_date"
- }
相應(yīng)的URL配置:
- (r'^books/$', date_based.archive_index, book_info),
必需的參數(shù):
date_field
在QuerySet的模型中的DateField或者DateTimeField的名字,基于日期的存檔使用它來(lái)決定頁(yè)面上的對(duì)象
queryset
存檔處理的QuerySet的對(duì)象
可選參數(shù):
allow_future
一個(gè)布爾值,它指定是否在這個(gè)頁(yè)面引入"未來(lái)"的對(duì)象,上面提到了
num_latest
傳遞到模板context的最近的對(duì)象數(shù)目,默認(rèn)為15
這個(gè)視圖也可以使用這些通用的參數(shù)(上面列出了):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
模板名:
如果template_name沒(méi)有指定,視圖將默認(rèn)使用(app_label)/(model_name)_archive.html
模板context:
除了extra_context,模板的context為如下列表:
date_list
datetime.date對(duì)象的列表,表示對(duì)應(yīng)queryset的所有具有對(duì)象的years,他們排反序
例如,如果你有一個(gè)從2003到2006的blog列表,這個(gè)列表將包含4個(gè)datetime.date對(duì)象:每年一個(gè)
latest
系統(tǒng)中的num_latest個(gè)對(duì)象,通過(guò)date_field排倒序
例如如果num_latest為10,latest將為queryset中的最近的10個(gè)對(duì)象
年存檔
django.views.generic.date_based.archive_year視圖提供一個(gè)每年的存檔頁(yè)面,顯示一個(gè)給定year的所有可得到的months
例子:
繼續(xù)我們的例子,我們想添加一種在一個(gè)給定的year查看所有發(fā)表的books的方式
我們可以繼續(xù)使用上面例子中的book_info字典,但是這一次我們把它包裝到archive_year視圖:
- (r'^books/(?P<year>\d{4})/?$', date_based.archive_year, book_info),
既然每年都可能有很多很多books發(fā)表,我們不會(huì)在這個(gè)頁(yè)面顯示他們,而只是顯示可得到books的years列表
很方便的是,這是Django默認(rèn)做的事情,我們可以使用mak_object_list參數(shù)改變它,參考下面的內(nèi)容
必需的參數(shù)
date_field
同上
queryset
存檔處理的QuerySet的對(duì)象
year
存檔處理的4個(gè)數(shù)字的year(通常從URL參數(shù)得到)
可選參數(shù):
make_object_list
一個(gè)布爾值,它指定了是否得到這一年的完整的對(duì)象列表并傳遞給模板,如果為True,對(duì)象列表將在模板中作為object_list來(lái)
得到(object_list名字可能不同,參考下面的"模板context"中關(guān)于object_list的信息),默認(rèn)為False
allow_future
一個(gè)布爾值,它指定是否在該頁(yè)面引入"未來(lái)"對(duì)象,上面提到了
這個(gè)視圖也可能使用這些通用參數(shù)(上面提到了):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
模板名:
如果template_name沒(méi)有指定,視圖將默認(rèn)使用(app_label)/(model_name)_archive_year.html
模板context:
除了extra_context,模板的context將為:
date_list
datetime.date對(duì)象的列表,表示在一個(gè)給定year的根據(jù)queryset的所有可得到對(duì)象的months,升序
year
一個(gè)給定的year,為一個(gè)4字符的string
object_list
如果make_object_list參數(shù)為True,它將設(shè)置為一個(gè)給定year的通過(guò)date_field排序的所有可得到的對(duì)象
這個(gè)變量的名字取決于template_objects_name參數(shù),后者默認(rèn)為'object'
如果template_object_name為'foo',則這個(gè)變量的名字為foo_list
如果make_object_list為False,則object_list將作為一個(gè)空l(shuí)ist傳遞給模板
月存檔
django.views.generic.date_based.archive_month視圖提供一個(gè)每月存檔頁(yè)面來(lái)顯示一個(gè)給定月份的所有對(duì)象
例子:
繼續(xù)我們的例子,創(chuàng)建一個(gè)month視圖將看起來(lái)很熟悉:
- (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', date_based.archive_month, book_info),
必需的參數(shù):
year
存檔處理的4數(shù)字的year(一個(gè)字符串)
month
存檔處理的月份,通過(guò)month_format參數(shù)來(lái)格式化
queryset
存檔處理的QuerySet的對(duì)象
date_field
在QuerySet的模型中的DateField或者DateTimeField的名字,基于日期的存檔使用它來(lái)決定頁(yè)面上的對(duì)象
可選參數(shù):
month_format
一個(gè)規(guī)定了month參數(shù)使用什么格式的格式字符串,它應(yīng)該遵循Python的time.strftime語(yǔ)法
(在http://www.python.org/doc/current/lib/module-time.html#l2h-1941查看Python的strftime文檔)
它默認(rèn)設(shè)為"%b",表示3個(gè)字母的月份縮寫(xiě)(即"jan","feb"等等),可以使用"%m"來(lái)更改它而使用數(shù)字
allow_future
一個(gè)布爾值,指定是否在頁(yè)面中引入"未來(lái)"的對(duì)象,上面提到了
這個(gè)視圖也可以使用這些通用的參數(shù)(上面提到了):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
模板名
如果template_name沒(méi)有指定,視圖默認(rèn)使用(app_label)/(model_name)_archive_month.html模板
模板context
除了extra_context,模板的context將為:
month
表示給定的月份的datetime.date對(duì)象
next_month
表示下個(gè)月第一天的datetime.date對(duì)象,如果下個(gè)月在未來(lái),它將為None
previous_month
表示上個(gè)月第一天的datetime.date對(duì)象,不像next_month,它永遠(yuǎn)不會(huì)為None
object_list
給定月份的可得到的對(duì)象列表,這個(gè)變量的名字取決于template_object_name參數(shù),后者默認(rèn)為'object'
如果template_object_name為'foo',這個(gè)變量名則為foo_list
星期存檔
django.views.generic.date_based.archive_week視圖顯示一個(gè)給定星期的所有對(duì)象
注意,Django認(rèn)為一個(gè)星期從星期日開(kāi)始,因?yàn)镻ython也這樣認(rèn)為
例子:
你開(kāi)始看這里的模式了沒(méi)?
- (r'^(?P<year>\d{4})/(?P<week>\d{2})/$', date_based.archive_week, book_info),
必需的參數(shù):
year
存檔處理的4數(shù)字的year(一個(gè)字符串)
week
存檔處理一年的星期(一個(gè)字符串)
queryset
存檔處理的QuerySet的對(duì)象
date_field
QuerySet的模型中的DateField或者DateTimeField的名字,基于日期的存檔使用它來(lái)決定頁(yè)面上顯示的對(duì)象
可選參數(shù):
allow_future
一個(gè)布爾值,指定是否在頁(yè)面中引入"未來(lái)"的對(duì)象,上面提到了
這個(gè)視圖也可以使用這些通用的參數(shù)(上面提到了):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
模板名
如果template_name沒(méi)有指定,這個(gè)視圖將默認(rèn)使用(app_label)/(model_name)_archive_week.html
模板context
除了extra_context,這個(gè)模板的context將為:
week
表示給定的星期的第一天的datetime.date對(duì)象
object_list
給定的星期的可得到的對(duì)象的列表,這個(gè)變量的名字取決于template_object_name參數(shù),或者默認(rèn)為'object'
如果template_object_name為'foo',則這個(gè)變量的名字為foo_list
天存檔
django.views.generiv.date_based.archive_day視圖提供了顯示一個(gè)給定天的所有對(duì)象的頁(yè)面
例子:
- (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{2})/$', date_based.archive_day, book_info),
必需的參數(shù):
year
存檔處理的4數(shù)字的year(一個(gè)字符串)
month
存檔處理的月份,通過(guò)month_format參數(shù)來(lái)格式化
day
存檔處理的天,通過(guò)day_format參數(shù)格式化
queryset
存檔處理的QuerySet的對(duì)象
date_field
QuerySet的模型的DateField或者DateTimeField的名字,基于日期的存檔使用它來(lái)決定頁(yè)面上顯示的對(duì)象
可選參數(shù):
month_format
一個(gè)規(guī)定了month參數(shù)使用的格式的格式化字符串,參考上面解釋的細(xì)節(jié)
day_format
類似于month_format,但是它與day參數(shù)工作,默認(rèn)為"%d"(十進(jìn)制數(shù)字的月份的一天,01-31)
allow_future
一個(gè)布爾值,指定了頁(yè)面中是否引入"future"對(duì)象,上面提到了
這個(gè)視圖也可以使用這些通用的參數(shù)(上面提到了):
allow_empty
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
模板名
如果template_name沒(méi)有指定,這個(gè)視圖將默認(rèn)使用(app_label)/(model_name)_archive_day.html
模板context
除了extra_context,模板的context將為:
day
表示給定的天的datetime.date對(duì)象
next_day
表示下一天的datetime.date對(duì)象,如果下一天在未來(lái),它將為None
previous_day
表示上一天的datetime.date對(duì)象,不像next_day,它永遠(yuǎn)不會(huì)是None
object_list
給定天的可得到的對(duì)象列表,這個(gè)變量的名字取決于template_object_name參數(shù),后者默認(rèn)為'object'
如果template_object_name為'foo',這個(gè)變量的名字則為foo_list
今天的存檔
django.views.generic.date_based.archive_today視圖顯示了今天的所有對(duì)象,它與archive_day一模一樣,除了year/month/day
參數(shù)不再被使用,而是使用今天的日期
基于日期的細(xì)節(jié)頁(yè)面
django.views.generic.date_based.object_detail視圖顯示了一個(gè)呈現(xiàn)一個(gè)單獨(dú)對(duì)象的頁(yè)面,它與object_detail頁(yè)面在URL上不同
object_detail視圖使用像/entries/(slug)/的URL,而這個(gè)使用像/entries/2006/aug/27/(slug)/的URL
注意,如果你在使用基于日期的細(xì)節(jié)頁(yè)面是在URL上有slugs,你可能也想在slug域上使用unique_for_date選項(xiàng)來(lái)驗(yàn)證slugs不會(huì)
在一個(gè)單獨(dú)的天重復(fù),參考附錄2得到unique_for_date的細(xì)節(jié)
例子:
這個(gè)例子和上面的例子稍微不同,我們需要提供一個(gè)對(duì)象ID或者一個(gè)slug來(lái)讓Django查找到對(duì)象
既然我們正在使用的對(duì)象沒(méi)有slug域,我們將使用稍微丑陋的基于ID的URL
在實(shí)踐中我們推薦使用slug域,但是為了途簡(jiǎn)單我們這里只是使它跑起來(lái)
讓我們配置下面的URL:
- (r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/(?P<day>\d{2})/(?P<object_id>[\w-]+)/$', date_based.object_detail, book_info),
必需的參數(shù):
year
對(duì)象的4個(gè)數(shù)字的year(一個(gè)字符串)
month
通過(guò)month_format參數(shù)格式化的對(duì)象的month
day
通過(guò)day_format參數(shù)格式化的對(duì)象的day
queryset
包含對(duì)象的QuerySet
date_field
QuerySet的模型的DateField或者DateTimeField的名字,generic view使用它根據(jù)year,month和day來(lái)查找對(duì)象
object_id
對(duì)象的主鍵域的值
或者slug
給定對(duì)象的slug,如果你傳遞這個(gè)域,slug_field參數(shù)(參看下面)也是必需的
可選參數(shù)
allow_future
一個(gè)布爾值,它指定是否在頁(yè)面中引入"未來(lái)"對(duì)象,上面提到了
day_format
類似于month_format,但是與day參數(shù)工作,默認(rèn)為"%d"(十進(jìn)制數(shù)字的month的day,01-31)
month_format
一個(gè)規(guī)定了month參數(shù)使用什么格式的格式化字符串,參考上面解釋的細(xì)節(jié)
slug_field
對(duì)象包含的slug的域的名字,如果你使用slug參數(shù),則它是必需的,但是如果你使用object_id參數(shù)它則不能使用
template_name_field
模板名使用的對(duì)象中的域的名字,它讓你在數(shù)據(jù)中存儲(chǔ)模板名字,換句話說(shuō),如果你的對(duì)象有一個(gè)'the_template'域并且值為
'foo.html'字符串,并且你設(shè)置template_name_field為'the_template',則這個(gè)對(duì)象的generic view將使用'foo.html'模板
這很繞,但是某些情況下很有用
這個(gè)視圖也可以使用這些通用的參數(shù)(上面提到了):
context_processors
extra_context
mimetype
template_loader
template_name
template_object_name
模板名
如果template_name沒(méi)有指定,視圖將默認(rèn)使用(app_label)/(model_name)_detail.html
模板context
除了extra_context,模板的context將為:
object
表示那個(gè)對(duì)象,這個(gè)變量的名字取決于template_object_name參數(shù),后者默認(rèn)為'object'
如果template_object_name為'foo',則這個(gè)變量的名字為foo
創(chuàng)建/更新/刪除generic views
注意,這些視圖會(huì)在Django的架構(gòu)修訂完成后有稍許改變(目前在開(kāi)發(fā)django.newforms),這個(gè)部分有隨之更新
django.views.generic.create_update模塊包含了一些增,刪,改對(duì)象的方法
創(chuàng)建對(duì)象視圖
django.views.generic.create_update.create_object視圖顯示一個(gè)創(chuàng)建對(duì)象,包含驗(yàn)證錯(cuò)誤(如果有錯(cuò)誤)的重新顯示以及保存
對(duì)象的表單,它使用Django模型的自動(dòng)manipulators
這些視圖如果通過(guò)GET訪問(wèn)則都會(huì)顯示表單,通過(guò)POST訪問(wèn)則會(huì)處理請(qǐng)求的動(dòng)作(增/刪/改)
注意,這些視圖對(duì)安全都沒(méi)有太多好主意,盡管有一個(gè)login_required屬性來(lái)限制訪問(wèn),但這是最好的情況了
例如,它們不會(huì)檢查編輯對(duì)象的用戶是創(chuàng)建該對(duì)象的同一用戶,也不會(huì)驗(yàn)證任何類別的權(quán)限
盡管如此,大多數(shù)時(shí)候這些特性可以通過(guò)對(duì)generic view寫(xiě)一個(gè)小的包裝來(lái)完成,參考下面的"擴(kuò)展generic view"得到更多信息
例子:
如果我們想允許用戶在數(shù)據(jù)庫(kù)創(chuàng)建新的books,我們可以做下面的事情:
- (r'^books/create/$', create_update.create_object, {'model' : Book}),
必需的參數(shù):
model
表單將創(chuàng)建的對(duì)象的Django模型
注意,這個(gè)視圖使用將創(chuàng)建的模型而不是QuerySet(上面的list/detail/date-based視圖使用)
可選參數(shù):
post_save_redirect
在保存對(duì)象之后視圖將返回的URL,默認(rèn)為object.get_absolute_url()
post_save_redirect
可能包含字典字符串格式,而不是對(duì)象的域?qū)傩裕缒憧梢允褂胮ost_save_redirect="/polls/%(slug)s/"
login_required
一個(gè)布爾值,指定用戶是否必須登錄來(lái)查看頁(yè)面和保存更改,它牽涉到了Django的認(rèn)證系統(tǒng),默認(rèn)為False
如果它是True,一個(gè)沒(méi)有登錄的用戶嘗試訪問(wèn)該頁(yè)面或者保存表單,Django將重定向到/accounts/login/
這個(gè)視圖也可以使用這些通用的參數(shù)(上面提到了):
context_processors
extra_context
template_loader
template_name
模板名
如果template_name沒(méi)有指定,視圖將默認(rèn)使用(app_label)/(model_name)_form.html模板
模板context
除了extra_context,模板的context將為:
form
一個(gè)表示用來(lái)編輯對(duì)象的表單的FormWrapper實(shí)例,它讓你在模板系統(tǒng)中輕松得到表單域
例如,如果模型有name和address兩個(gè)域:
- <form action="" method="post">
- <p><label for="id_name">Name:</label> {{ form.name }}</p>
- <p><label for="id_address">Address:</label> {{ form.address }}</p>
- </form>
參考第7章來(lái)得到更多關(guān)于表單的信息
更新對(duì)象視圖
django.views.generic.create_update.update_object視圖幾乎和上面的create_object視圖一樣,但是這個(gè)允許編輯一個(gè)已經(jīng)
存在的對(duì)象而不是創(chuàng)建一個(gè)新的對(duì)象
例子:
繼續(xù)上面的例子,我們可以配置URL來(lái)提供一個(gè)單獨(dú)的book的編輯界面:
- (r'^books/edit/(?P<object_id>\d+)/$', create_update.update_object, {'model' : Book}),
必須的參數(shù):
model
表單將編輯的Django模型
object_id
對(duì)象的主鍵域的值
或者slug
給定對(duì)象的slug,如果你傳遞這個(gè)域,slug_field參數(shù)(下面提到)也是必需的
可選參數(shù):
slug_field
對(duì)象中包含slug的域的名字,如果你使用slug參數(shù),這個(gè)參數(shù)則是必需的,但是如果你使用object_id參數(shù)就不能使用它
另外,這個(gè)視圖也可以使用上面的創(chuàng)建對(duì)象視圖同樣的可選參數(shù),加上template_object_name這個(gè)通用參數(shù)
模板名
這個(gè)視圖使用和創(chuàng)建視圖相同的默認(rèn)模板名(app_label)/(model_name)_form.html
模板context
除了extra_context,模板的context將為:
form
表示編輯對(duì)象的表單的FormWrapper實(shí)例,參考上面的創(chuàng)建對(duì)象來(lái)得到更多關(guān)于這個(gè)值的信息
object
被編輯的對(duì)象(如果你提供了template_object_name參數(shù),這個(gè)參數(shù)可能會(huì)命名不同)
刪除對(duì)象視圖
django.views.generic.create_update.delete_object視圖和上面兩個(gè)很類似
如果這個(gè)視圖通過(guò)GET訪問(wèn),它將顯示一個(gè)確認(rèn)頁(yè)面(即"do you really want to delete this object?")
如果這個(gè)視圖通過(guò)POST提交,這個(gè)對(duì)象將沒(méi)有確認(rèn)而被刪除掉
所有的參數(shù)和更新對(duì)象視圖一樣,context也如此
這個(gè)視圖的模板名為(app_label)/(model_name)_confirm_delete.html
擴(kuò)展generic views
毫無(wú)疑問(wèn),使用generic views的確可以加快開(kāi)發(fā)速度,盡管如此,在大部分項(xiàng)目中,會(huì)出現(xiàn)generic views不能滿足的情況
確實(shí),新的Django開(kāi)發(fā)人員最常問(wèn)的問(wèn)題是怎樣讓generic views處理更寬廣的情形
幸運(yùn)的是,幾乎這些情況中的每一種都有方法來(lái)簡(jiǎn)單的繼承g(shù)eneric views來(lái)處理大量的用例,這些情況通常有如下幾個(gè)模式
添加額外的context
通常你只需在generic view種顯示一些額外的信息,例如,考慮顯示一個(gè)book和它所有publishers的列表的細(xì)節(jié)頁(yè)面
object_detail這個(gè)generic view把book傳遞給context,但是看起來(lái)沒(méi)有方法在模板種得到一個(gè)publishers列表
但是,所有的generic views使用一個(gè)額外選項(xiàng)參數(shù)extra_context,它是一個(gè)額外對(duì)象的字典并將被添加到模板的context中
所以,我們使用下面這樣的info dict來(lái)提供book的publishers列表:
- book_info = {
- "queryset" : Book.objects.all(),
- "date_field" : "publication_date",
- "extra_context" : {
- "publisher_list" : Publisher.objects.all(),
- }
- }
它將把{{ publisher_list }}變量傳遞到模板context中去,這個(gè)模式可以用來(lái)為generic view傳遞任何信息到模板,非常便利
使用包裝方法的更復(fù)雜的過(guò)濾器
另一個(gè)常見(jiàn)的需求是通過(guò)URL中的鍵來(lái)過(guò)濾給定的列表對(duì)象,例如,我們提供一個(gè)通過(guò)title瀏覽books的接口
我們想提供/books/by-title/a/,/books/by-title/b/等等形式的URL,每個(gè)字母為一個(gè)列表頁(yè)面
問(wèn)題看起來(lái)generic view沒(méi)有從URL閱讀變量的方法,如果我們包裝一個(gè)URL模式來(lái)匹配這些URL到object_list視圖,我們將得到
26個(gè)顯示book的頁(yè)面(每個(gè)頁(yè)面有一個(gè)不同的queryset參數(shù)),這很愚蠢
正確的技術(shù)涉及到給generic view寫(xiě)一個(gè)簡(jiǎn)單的"包裝器"方法
在我們的字母表瀏覽的例子中,我們先在URL配置中添加一點(diǎn)東西:
- from bookstore.views import browse_alphabetically
- urlpatterns = patterns('',
- # ...
- (r'^books/by-title/([a-z])/$', browse_alphabetically)
- )
你可以看到,它包裝了browse_aplhabetically方法的一系列URL,所以讓我們看看這個(gè)方法怎么寫(xiě):
- from bookstore.models. import Book
- from django.views.generic import list_detail
- def browse_alphabetically(request, letter):
- return list_detail.object_list(
- request,
- queryset = Book.objects.filter(title__istartswith=letter),
- template_name = "bookstore/browse_alphabetically.html",
- extra_context = {
- 'letter' : letter,
- }
- )
就是這個(gè)!
它會(huì)工作,因?yàn)閷?duì)于generic views沒(méi)有任何特別的東西,它們只是Python方法
像其它任何視圖方法一樣,generic views期望一些參數(shù)并返回HttpResponse對(duì)象
這樣,非常容易就可以對(duì)一個(gè)generic view包裝一個(gè)小方法來(lái)在前面或后面做額外的工作,處理generic view額外的事情
注意,上面的例子中我們傳遞在extra_context中顯示的當(dāng)前的字母,包裝是個(gè)好主意,它讓模板知道當(dāng)前哪個(gè)字母正在被瀏覽
同時(shí)也注意一下,我們傳遞了自定義的模板的名字,否則它將使用和"vanilla" object_list一樣的模板,這將引起沖突
處理額外的工作
最后一個(gè)常見(jiàn)的模式,讓我們看看在調(diào)用generic view之前和之后做一些額外的工作
假想我們?cè)贏uthor對(duì)象有一個(gè)last_accessed域,我們使用它來(lái)記錄某人最后一次查看該author的時(shí)間,
object_detail這個(gè)generic view當(dāng)然不知道這個(gè)域的任何事情,但是再一次的我們可以很輕松的寫(xiě)自定義的視圖來(lái)讓這個(gè)域更新
首先,我們需要修改author detail的URL配置來(lái)指向一個(gè)自定義視圖:
- from bookstore.views import author_detail
- urlpatterns = patterns('',
- #...
- (r'^authors/(?P<author_id>d+)/$', author_detail),
- )
然后我們寫(xiě)我們自己的包裝方法:
- import datetime
- from bookstore.models import Author
- from django.views.generic import list_detail
- from django.shortcuts import get_object_or_404
- def author_detail(request, author_id):
- # Look up the Author (and raise a 404
安徽新華電腦學(xué)校專業(yè)職業(yè)規(guī)劃師為你提供更多幫助【在線咨詢】