這篇教程承接?教程第 6 部分?結(jié)束的地方检盼。我們繼續(xù)修改在線投票應(yīng)用旷坦,這次我們專注于自定義我們?cè)?教程第 2 部分?初見過(guò)的 Django 自動(dòng)生成后臺(tái)的過(guò)程。
自定義后臺(tái)表單?
通過(guò)?admin.site.register(Question)?注冊(cè)?Question?模型梁只,Django 能夠構(gòu)建一個(gè)默認(rèn)的表單用于展示熊响。通常來(lái)說(shuō),你期望能自定義表單的外觀和工作方式英染。你可以在注冊(cè)模型時(shí)將這些設(shè)置告訴 Django揽惹。
讓我們通過(guò)重排列表單上的字段來(lái)看看它是怎么工作的。用以下內(nèi)容替換?admin.site.register(Question):
polls/admin.py
fromdjango.contribimportadminfrom.modelsimportQuestionclassQuestionAdmin(admin.ModelAdmin):fields=['pub_date','question_text']admin.site.register(Question,QuestionAdmin)
你需要遵循以下流程——?jiǎng)?chuàng)建一個(gè)模型后臺(tái)類四康,接著將其作為第二個(gè)參數(shù)傳給?admin.site.register()?——在你需要修改模型的后臺(tái)管理選項(xiàng)時(shí)這么做搪搏。
以上修改使得 "Publication date" 字段顯示在 "Question" 字段之前:
這在只有兩個(gè)字段時(shí)顯得沒(méi)啥卵用,但對(duì)于擁有數(shù)十個(gè)字段的表單來(lái)說(shuō)闪金,為表單選擇一個(gè)直觀的排序方法就顯得你的針很細(xì)了疯溺。
說(shuō)到擁有數(shù)十個(gè)字段的表單,你可能更期望將表單分為幾個(gè)字段集:
polls/admin.py
fromdjango.contribimportadminfrom.modelsimportQuestionclassQuestionAdmin(admin.ModelAdmin):fieldsets=[(None,{'fields':['question_text']}),('Date information',{'fields':['pub_date']}),]admin.site.register(Question,QuestionAdmin)
fieldsets?元組中的第一個(gè)元素是字段集的標(biāo)題哎垦。以下是我們的表單現(xiàn)在的樣子:
添加關(guān)聯(lián)的對(duì)象?
好了囱嫩,現(xiàn)在我們有了投票的后臺(tái)頁(yè)。不過(guò)漏设,一個(gè)?Question?有多個(gè)?Choice墨闲,但后臺(tái)頁(yè)卻沒(méi)有顯示多個(gè)選項(xiàng)。
好了郑口。
有兩個(gè)方法可以解決這個(gè)問(wèn)題鸳碧。第一個(gè)就是仿照我們向后臺(tái)注冊(cè)?Question?一樣注冊(cè)?Choice?盾鳞。這很簡(jiǎn)單:
polls/admin.py
fromdjango.contribimportadminfrom.modelsimportChoice,Question# ...admin.site.register(Choice)
現(xiàn)在 "Choices" 在 Django 后臺(tái)頁(yè)中是一個(gè)可用的選項(xiàng)了≌袄耄“添加選項(xiàng)”的表單看起來(lái)像這樣:
在這個(gè)表單中雁仲,"Question" 字段是一個(gè)包含數(shù)據(jù)庫(kù)中所有投票的選擇框。Django 知道要將?ForeignKey?在后臺(tái)中以選擇框?<select>?的形式展示琐脏。此時(shí)攒砖,我們只有一個(gè)投票。
同時(shí)也注意下 "Question" 旁邊的“添加”按鈕日裙。每個(gè)使用?ForeignKey?關(guān)聯(lián)到另一個(gè)對(duì)象的對(duì)象會(huì)自動(dòng)獲得這個(gè)功能吹艇。當(dāng)你點(diǎn)擊“添加”按鈕時(shí),你會(huì)見到一個(gè)包含“添加投票”的表單昂拂。如果你在這個(gè)彈出框中添加了一個(gè)投票受神,并點(diǎn)擊了“保存”,Django 會(huì)將其保存至數(shù)據(jù)庫(kù)格侯,并動(dòng)態(tài)地在你正在查看的“添加選項(xiàng)”表單中選中它鼻听。
不過(guò),這是一種很低效地添加“選項(xiàng)”的方法联四。更好的辦法是在你創(chuàng)建“投票”對(duì)象時(shí)直接添加好幾個(gè)選項(xiàng)撑碴。讓我們實(shí)現(xiàn)它。
移除調(diào)用?register()?注冊(cè)?Choice?模型的代碼朝墩。隨后醉拓,像這樣修改?Question?的注冊(cè)代碼:
polls/admin.py
fromdjango.contribimportadminfrom.modelsimportChoice,QuestionclassChoiceInline(admin.StackedInline):model=Choiceextra=3classQuestionAdmin(admin.ModelAdmin):fieldsets=[(None,{'fields':['question_text']}),('Date information',{'fields':['pub_date'],'classes':['collapse']}),]inlines=[ChoiceInline]admin.site.register(Question,QuestionAdmin)
這會(huì)告訴 Django:“Choice?對(duì)象要在?Question?后臺(tái)頁(yè)面編輯。默認(rèn)提供 3 個(gè)足夠的選項(xiàng)字段收苏∫诼保”
加載“添加投票”頁(yè)面來(lái)看看它長(zhǎng)啥樣:
它看起來(lái)像這樣:有三個(gè)關(guān)聯(lián)的選項(xiàng)插槽——由?extra?定義,且每次你返回任意已創(chuàng)建的對(duì)象的“修改”頁(yè)面時(shí)鹿霸,你會(huì)見到三個(gè)新的插槽排吴。
在三個(gè)插槽的末端,你會(huì)看到一個(gè)“添加新選項(xiàng)”的按鈕懦鼠。如果你單擊它钻哩,一個(gè)新的插槽會(huì)被添加。如果你想移除已有的插槽葛闷,可以點(diǎn)擊插槽右上角的X憋槐。注意,你不能移除原始的 3 個(gè)插槽淑趾。以下圖片展示了一個(gè)已添加的插槽:
不過(guò)阳仔,仍然有點(diǎn)小問(wèn)題。它占據(jù)了大量的屏幕區(qū)域來(lái)顯示所有關(guān)聯(lián)的?Choice?對(duì)象的字段。對(duì)于這個(gè)問(wèn)題近范,Django 提供了一種表格式的單行顯示關(guān)聯(lián)對(duì)象的方法嘶摊。你只需按如下形式修改?ChoiceInline?申明:
polls/admin.py
classChoiceInline(admin.TabularInline):#...
通過(guò)?TabularInline``(替代?``StackedInline?),關(guān)聯(lián)對(duì)象以一種表格式的方式展示评矩,顯得更加緊湊:
注意這里有一個(gè)額外的“刪除叶堆?”列,這允許移除通過(guò)“添加新選項(xiàng)”按鈕添加的斥杜,或是已被保存的行虱颗。
自定義后臺(tái)更改列表?
現(xiàn)在投票的后臺(tái)頁(yè)看起來(lái)很不錯(cuò),讓我們對(duì)“更改列表”頁(yè)面進(jìn)行一些調(diào)整——改成一個(gè)能展示系統(tǒng)中所有投票的頁(yè)面蔗喂。
以下是它此時(shí)的外觀:
默認(rèn)情況下忘渔,Django 顯示每個(gè)對(duì)象的?str()?返回的值。但有時(shí)如果我們能夠顯示單個(gè)字段缰儿,它會(huì)更有幫助畦粮。為此,使用?list_display?后臺(tái)選項(xiàng)乖阵,它是一個(gè)包含要顯示的字段名的元組宣赔,在更改列表頁(yè)中以列的形式展示這個(gè)對(duì)象:
polls/admin.py
classQuestionAdmin(admin.ModelAdmin):# ...list_display=('question_text','pub_date')
為了更好用,讓我們也包含?教程第 2 部分?中的?was_published_recently()?方法:
polls/admin.py
classQuestionAdmin(admin.ModelAdmin):# ...list_display=('question_text','pub_date','was_published_recently')
現(xiàn)在修改投票的列表頁(yè)看起來(lái)像這樣:
你可以點(diǎn)擊列標(biāo)題來(lái)對(duì)這些行進(jìn)行排序——除了?was_published_recently?這個(gè)列瞪浸,因?yàn)闆](méi)有實(shí)現(xiàn)排序方法儒将。順便看下這個(gè)列的標(biāo)題?was_published_recently,默認(rèn)就是方法名(用空格替換下劃線)默终,該列的每行都以字符串形式展示出處椅棺。
你可以通過(guò)給這個(gè)方法(在?polls/models.py?中)一些屬性來(lái)達(dá)到優(yōu)化的目的,像這樣:
polls/models.py
classQuestion(models.Model):# ...defwas_published_recently(self):now=timezone.now()returnnow-datetime.timedelta(days=1)<=self.pub_date<=nowwas_published_recently.admin_order_field='pub_date'was_published_recently.boolean=Truewas_published_recently.short_description='Published recently?'
更多關(guān)于這些方法屬性的信息齐蔽,參見?list_display。
再次編輯文件?polls/admin.py床估,優(yōu)化?Question?變更頁(yè):過(guò)濾器含滴,使用?list_filter。將以下代碼添加至?QuestionAdmin:
list_filter=['pub_date']
這樣做添加了一個(gè)“過(guò)濾器”側(cè)邊欄丐巫,允許人們以?pub_date?字段來(lái)過(guò)濾列表:
展示的過(guò)濾器類型取決你你要過(guò)濾的字段的類型谈况。因?yàn)?pub_date?是類?DateTimeField,Django 知道要提供哪個(gè)過(guò)濾器:“任意時(shí)間”递胧,“今天”碑韵,“過(guò)去7天”,“這個(gè)月”和“今年”缎脾。
這已經(jīng)弄的很好了祝闻。讓我們?cè)贁U(kuò)充些功能:
search_fields=['question_text']
在列表的頂部增加一個(gè)搜索框。當(dāng)輸入待搜項(xiàng)時(shí)遗菠,Django 將搜索?question_text?字段联喘。你可以使用任意多的字段——由于后臺(tái)使用?LIKE?來(lái)查詢數(shù)據(jù)华蜒,將待搜索的字段數(shù)限制為一個(gè)不會(huì)出問(wèn)題大小,會(huì)便于數(shù)據(jù)庫(kù)進(jìn)行查詢操作豁遭。
現(xiàn)在是給你的修改列表頁(yè)增加分頁(yè)功能的好時(shí)機(jī)叭喜。默認(rèn)每頁(yè)顯示 100 項(xiàng)。變更頁(yè)分頁(yè),?搜索框,?過(guò)濾器,?日期層次結(jié)構(gòu), 和?列標(biāo)題排序?均以你期望的方式合作運(yùn)行蓖谢。
自定義后臺(tái)界面和風(fēng)格?
在每個(gè)后臺(tái)頁(yè)頂部顯示“Django 管理員”顯得很滑稽捂蕴。這只是一串占位文本。
不過(guò)闪幽,這可以通過(guò) Django 的模板系統(tǒng)很方便的修改啥辨。Django 的后臺(tái)由自己驅(qū)動(dòng),且它的交互接口采用 Django 自己的模板系統(tǒng)沟使。
自定義你的?工程的?模板?
在你的工程目錄(指包含?manage.py?的那個(gè)文件夾)內(nèi)創(chuàng)建一個(gè)名為?templates?的目錄委可。模板可放在你系統(tǒng)中任何 Django 能找到的位置。(誰(shuí)啟動(dòng)了 Django腊嗡,Django 就以他的用戶身份運(yùn)行着倾。)不過(guò),把你的模板放在工程內(nèi)會(huì)帶來(lái)很大便利燕少,推薦你這樣做卡者。
打開你的設(shè)置文件(mysite/settings.py,牢記)客们,在?TEMPLATES?設(shè)置中添加?DIRS?選項(xiàng):
mysite/settings.py
TEMPLATES=[{'BACKEND':'django.template.backends.django.DjangoTemplates','DIRS':[os.path.join(BASE_DIR,'templates')],'APP_DIRS':True,'OPTIONS':{'context_processors':['django.template.context_processors.debug','django.template.context_processors.request','django.contrib.auth.context_processors.auth','django.contrib.messages.context_processors.messages',],},},]
DIRS?是一個(gè)包含多個(gè)系統(tǒng)目錄的文件列表崇决,用于在載入 Django 模板時(shí)使用,是一個(gè)待搜索路徑底挫。
組織模板
就像靜態(tài)文件一樣恒傻,我們?可以?把所有的模板文件放在一個(gè)大模板目錄內(nèi),這樣它也能工作的很好建邓。但是盈厘,屬于特定應(yīng)用的模板文件最好放在應(yīng)用所屬的模板目錄(例如?polls/templates),而不是工程的模板目錄(templates)官边。我們會(huì)在?創(chuàng)建可復(fù)用的應(yīng)用教程?中討論?為什么?我們要這樣做沸手。
現(xiàn)在,在?templates?目錄內(nèi)創(chuàng)建名為?admin?的目錄注簿,隨后契吉,將存放 Django 默認(rèn)模板的目錄(django/contrib/admin/templates)內(nèi)的模板文件?admin/base_site.html?復(fù)制到這個(gè)目錄內(nèi)。
Django 的源文件在哪里诡渴?
如果你不知道 Django 源碼在你系統(tǒng)的哪個(gè)位置捐晶,運(yùn)行以下命令:
$python -c"import django; print(django.__path__)"
接著,用你站點(diǎn)的名字替換文件內(nèi)的?``{{ site_header|default:_('Django administration') }}``(包含大括號(hào))。完成后租悄,你應(yīng)該看到如下代碼:
{%blockbranding%}<h1id="site-name"><ahref="{%url'admin:index'%}">Polls Administration</a></h1>{%endblock%}
我們會(huì)用這個(gè)方法來(lái)教你復(fù)寫模板谨究。在一個(gè)實(shí)際工程中,你可能更期望使用?django.contrib.admin.AdminSite.site_header?來(lái)進(jìn)行簡(jiǎn)單的定制泣棋。
這個(gè)模板文件包含很多類似?{%?block?branding?%}?和?{{?title?}}?的文本胶哲。?{%?和?{{?標(biāo)簽是 Django 模板語(yǔ)言的一部分。當(dāng) Django 渲染?admin/base_site.html?時(shí)潭辈,這個(gè)模板語(yǔ)言會(huì)被求值鸯屿,生成最終的網(wǎng)頁(yè),就像我們?cè)?教程第 3 部分?所學(xué)的一樣把敢。
注意寄摆,所有的 Django 默認(rèn)后臺(tái)模板均可被復(fù)寫。若要復(fù)寫模板修赞,像你修改?base_site.html?一樣修改其它文件——先將其從默認(rèn)目錄中拷貝到你的自定義目錄婶恼,再做修改。
自定義你?應(yīng)用的?模板?
機(jī)智的同學(xué)可能會(huì)問(wèn):?DIRS?默認(rèn)是空的柏副,Django 是怎么找到默認(rèn)的后臺(tái)模板的勾邦?因?yàn)?APP_DIRS?被置為?True,Django 會(huì)自動(dòng)在每個(gè)應(yīng)用包內(nèi)遞歸查找?templates/?子目錄(不要忘了?django.contrib.admin?也是一個(gè)應(yīng)用)割择。
我們的投票應(yīng)用不是非常復(fù)雜眷篇,所以無(wú)需自定義后臺(tái)模板。不過(guò)荔泳,如果它變的更加復(fù)雜蕉饼,需要修改 Django 的標(biāo)準(zhǔn)后臺(tái)模板功能時(shí),修改?應(yīng)用?的模板會(huì)比?工程?的更加明智玛歌。這樣昧港,在其它工程包含這個(gè)投票應(yīng)用時(shí),可以確保它總是能找到需要的自定義模板文件支子。
更多關(guān)于 Django 如何查找模板的文檔慨飘,參見?加載模板文檔。
自定義后臺(tái)主頁(yè)?
在類似的說(shuō)明中译荞,你可能想要自定義 Django 后臺(tái)索引頁(yè)的外觀。
默認(rèn)情況下休弃,它展示了所有配置在?INSTALLED_APPS?中吞歼,已通過(guò)后臺(tái)應(yīng)用注冊(cè),按拼音排序的應(yīng)用塔猾。你可能想對(duì)這個(gè)頁(yè)面的布局做重大的修改篙骡。畢竟,索引頁(yè)是后臺(tái)的重要頁(yè)面,它應(yīng)該便于使用糯俗。
需要自定義的模板是?admin/index.html尿褪。(像上一節(jié)修改?admin/base_site.html?那樣修改此文件——從默認(rèn)目錄中拷貝此文件至自定義模板目錄)。打開此文件得湘,你將看到它使用了一個(gè)叫做?app_list?的模板變量杖玲。這個(gè)變量包含了每個(gè)安裝的 Django 應(yīng)用。你可以用任何你期望的硬編碼鏈接(鏈接至特定對(duì)象的管理頁(yè))替代使用這個(gè)變量淘正。
接下來(lái)要做什么摆马??
初學(xué)者教程到這就結(jié)束了。隨后鸿吆,你可能想閱讀?下一步看什么囤采,看看下一步能做什么。
如果你很熟悉 Python 打包惩淳,且對(duì)學(xué)習(xí)如何把投票應(yīng)用改成“可復(fù)用應(yīng)用”感興趣蕉毯,查看?進(jìn)階教程:如何創(chuàng)建可復(fù)用應(yīng)用。