第七章

這篇教程承接?教程第 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)用

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末思犁,一起剝皮案震驚了整個(gè)濱河市代虾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌抒倚,老刑警劉巖褐着,帶你破解...
    沈念sama閱讀 206,214評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異托呕,居然都是意外死亡含蓉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,307評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門项郊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)馅扣,“玉大人,你說(shuō)我怎么就攤上這事着降〔钣停” “怎么了?”我有些...
    開封第一講書人閱讀 152,543評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵任洞,是天一觀的道長(zhǎng)蓄喇。 經(jīng)常有香客問(wèn)我,道長(zhǎng)交掏,這世上最難降的妖魔是什么妆偏? 我笑而不...
    開封第一講書人閱讀 55,221評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮盅弛,結(jié)果婚禮上钱骂,老公的妹妹穿的比我還像新娘叔锐。我一直安慰自己,他們只是感情好见秽,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,224評(píng)論 5 371
  • 文/花漫 我一把揭開白布愉烙。 她就那樣靜靜地躺著,像睡著了一般解取。 火紅的嫁衣襯著肌膚如雪步责。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,007評(píng)論 1 284
  • 那天肮蛹,我揣著相機(jī)與錄音勺择,去河邊找鬼。 笑死伦忠,一個(gè)胖子當(dāng)著我的面吹牛省核,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播昆码,決...
    沈念sama閱讀 38,313評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼气忠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了赋咽?” 一聲冷哼從身側(cè)響起旧噪,我...
    開封第一講書人閱讀 36,956評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脓匿,沒(méi)想到半個(gè)月后淘钟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,441評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陪毡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,925評(píng)論 2 323
  • 正文 我和宋清朗相戀三年米母,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片毡琉。...
    茶點(diǎn)故事閱讀 38,018評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡铁瞒,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出桅滋,到底是詐尸還是另有隱情慧耍,我是刑警寧澤,帶...
    沈念sama閱讀 33,685評(píng)論 4 322
  • 正文 年R本政府宣布丐谋,位于F島的核電站芍碧,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏号俐。R本人自食惡果不足惜师枣,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,234評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望萧落。 院中可真熱鬧践美,春花似錦、人聲如沸找岖。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,240評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)许布。三九已至兴革,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蜜唾,已是汗流浹背杂曲。 一陣腳步聲響...
    開封第一講書人閱讀 31,464評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留袁余,地道東北人擎勘。 一個(gè)月前我還...
    沈念sama閱讀 45,467評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像颖榜,于是被迫代替她去往敵國(guó)和親棚饵。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,762評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容