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