Part7 定制Django的自動生成式管理站點

這篇教程從第6節(jié)結(jié)束的地方開始,我們繼續(xù)開發(fā)Web投票應(yīng)用偷线,我們將注意力放在定制Django的自動生成式管理站點,我們在第2節(jié)的時候用過一次。

定制admin表單

通過使用 admin.site.register(Question)來注冊Question优训,Django可以組織一個默認的表格展示形式。很常見的情況是各聘,你希望定制admin表單看起來的樣子以及它的工作方式揣非。你可以通過在注冊對象的時候通過告知Django相關(guān)的選項來完成這樣的定制。

讓我們來看一下是怎么做的躲因,通過重新調(diào)整編輯表單上的字段順序早敬。使用下面的代碼替換admin.site.register(Question)

from django.contrib import admin

from .models import Question

class QuestionAdmin(admin.ModelAdmin):
    fields = ['pub_date', 'question_text']

admin.site.register(Question, QuestionAdmin)

你可以遵循這種模式—— 創(chuàng)建一個模型管理類,然后把它作為admin.site.register()的第二個參數(shù)大脉。任何時候你需要修改模型的管理選項搞监。

上面特定的修改會讓“Publication date”字段在“Question”字段的前面,像下面這樣:


image.png

只有兩個字段的話不是特別明顯镰矿,但是對于由很多字段的管理表單的話琐驴,選擇一個直觀的順序是一個非常重要且有用的細節(jié)。

說到有很多字段的表單秤标,你可能會想將表單切割成字段集合:

from django.contrib import admin

from .models import Question


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date']}),
    ]

admin.site.register(Question, QuestionAdmin)

字段集合里的每一個元組的第一個元素是字段集合的標題绝淡,下面是我們的表單看起來的樣子。

image.png

添加關(guān)聯(lián)對象

好了苍姜,我們現(xiàn)在以及有了我們的Question管理頁面牢酵,但是一個Question有多個Choice,并且管理頁面并沒有顯示Choice衙猪。

有兩種方式來解決這種問題馍乙,第一種是使用admin來注冊Choice布近,就像我們剛才注冊Question一樣,這非常簡單:

from django.contrib import admin

from .models import Choice, Question
# ...
admin.site.register(Choice)

然后再Django管理頁面就能看到Choice選項了丝格,"Add choice"表單看起來像下面這樣:


image.png

在這個表單里撑瞧,"Question"字段是一個選擇框,里面包含了數(shù)據(jù)庫里的所有Question显蝌。Django知道在管理頁面將一個ForeignKey當(dāng)作一個選擇框季蚂。在我們的例子里,只有一個question琅束。

也要注意扭屁,在“Question”旁邊的“Add another”按鈕,每個帶有外鍵管理到其他對象的對象都會自動生成這個按鈕涩禀。當(dāng)你點擊“Add another”的時候料滥,你會得到一個彈出式窗口,關(guān)聯(lián)到“Add Question”表單艾船。如果你在這個表單里添加一個問題葵腹,然后點擊“Save”,Django會自動把這個question保存到數(shù)據(jù)庫屿岂,并且動態(tài)的將它也添加到你剛才看到的“Add Choice”表單的選擇框里践宴。

但是,實際上爷怀,這樣添加Choice對象到系統(tǒng)里阻肩,確實是一種低效的方式。在你添加Question對象的時候直接添加很多Choice运授,這樣的方式會更好烤惊,讓我們來試試。
移除Choice模型的register()調(diào)用吁朦,然后編輯Question注冊代碼柒室,像下面這:

from django.contrib import admin

from .models import Choice, Question


class ChoiceInline(admin.StackedInline):
    model = Choice
    extra = 3


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]

admin.site.register(Question, QuestionAdmin)

這告訴Django:“要在Question管理頁面編輯Choice對象。默認情況下逗宜,為3個choice提供足夠的字段雄右。”
加載"Add question"頁面纺讲,看一下它的樣式擂仍。


image.png

它看起來像這樣:關(guān)聯(lián)的Choices有3個槽——通過Choice的extra設(shè)置的數(shù)量。每次你返回到創(chuàng)建好的Question的“Change”頁面刻诊,你都會看到3個額外的槽防楷。

在當(dāng)前三個槽的結(jié)尾處牺丙,你會看到一個“Add another Choice”鏈接则涯,如果你點擊它复局,會添加另外一個新的槽。如果你想移除已經(jīng)添加的槽粟判,你可以點擊已經(jīng)添加的槽的右上方的X來刪除它亿昏。下面的圖片顯示一個已經(jīng)添加的槽:


image.png

但是還有一個小問題就是,它需要很多屏幕空間來顯示已經(jīng)創(chuàng)建好的档礁,和Question相關(guān)聯(lián)的Choice對象的所有字段角钩。基于這個原因呻澜,Django提供一個表格形式來顯示內(nèi)聯(lián)的對象递礼。你只需要修改ChoiceInline的聲明類型。:

class ChoiceInline(admin.TabularInline):
    #...

使用TabularInline(替換StackedInline)羹幸,關(guān)聯(lián)的對象會以更緊湊脊髓,基于表格的格式來顯示:


image.png

注意,有一個額外的"Delete"列栅受,用來刪除通過"Add Another Choice"按鈕添加的行将硝,或者已經(jīng)保存的行。

定制管理頁面的修改列表

現(xiàn)在Question的管理頁面看起來很棒屏镊,現(xiàn)在我們來對“change list”頁面做一些調(diào)整依疼。這個頁面是用來顯示系統(tǒng)里的所有questions的頁面。
下面是它現(xiàn)在看起來的樣子:


image.png

默認情況下而芥,Django顯示每個對象的str()律罢,但是有些時候我們可以顯示不同的字段的話可能更有幫助。要實現(xiàn)這樣的功能棍丐,我們使用list_display這個管理選項弟翘,這是一個用來在對象的“change list”頁面要顯示的字段名稱組成的元組。

class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date')

為了更方便骄酗,我們把第2節(jié)里的was_published_recently()方法也加上:

class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date', 'was_published_recently')

現(xiàn)在question的修改頁面看起來像下面的樣子:


image.png

你可以點擊列的頭部來通過值排序——除了was_published_recently頭部, 因為通過一個不確定的方法的輸出值來排序,目前還是不支持的.也要注意,was_published_recently這一列的頭部默認情況下就是方法的名稱(使用下劃線替換空格),并且每一行包含方法輸出的字符串格式.

你可以通過這個方法(在polls/models里)的一些屬性來提高頁面的可讀性,像下面這樣:

class Question(models.Model):
    # ...
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now
    was_published_recently.admin_order_field = 'pub_date'
    was_published_recently.boolean = True
    was_published_recently.short_description = 'Published recently?'

關(guān)于這個方法特性的更多信息,可以看list_display.
再次編輯你的polls/admin.py文件,然后添加一個修改后的方法到Question的修改列表頁面:通過使用list_filter來過濾Question. 把下面的行添加到QuestionAdmin里:

list_filter = ['pub_date']

這行代碼提供了一個"Filter"側(cè)邊欄,讓用戶可以通過pub_date字段過濾修改列表,如下所示:

image.png

過濾器的類型依賴于你要過濾的字段的類型,因為pub_date是一個DateTimeField,Django知道給出一個相近的選項:"Any date", "Today", "Past 7 days", "This Month", "This year".
這種篩選方式非常好,我們再添加一些搜索的兼容性:
search_fields = ['question_text']
這行代碼會再修改列表頂部添加一個搜索框.當(dāng)有人輸入搜索選項的時候,Django會搜索question_text字段稀余。你可以使用任意多個你想要的字段,但是因為在后臺使用的是LIKE查詢,所以限制了搜索字段的數(shù)量到合理的值趋翻,讓數(shù)據(jù)庫搜索的時候更簡單睛琳。

修改列表也給了你一個免費的分頁功能,默認的是顯示一頁100個選項踏烙。Change_list_pagination师骗,search_boxes,filters讨惩,date-hierarchies和column-headerr-ordering會像你認為的那樣工作(個人理解是根據(jù)他們函數(shù)的名稱那樣工作辟癌,比如filter就是用來過濾)。

定制管理頁面的外觀和感覺

顯然荐捻,在每個管理頁面的頂端都有"Django administration"很扯淡黍少,它們僅僅只是占位符內(nèi)容寡夹。
但是直接使用Django的模板系統(tǒng),這些也很容易修改厂置。Django的管理頁面是它自己支持的菩掏,并且它的接口使用Django自己的模板系統(tǒng)。

定制你自己的項目的模板

直接在你的項目目錄(包含manage.py的目錄)里創(chuàng)建一個templates目錄昵济,模板可以在你的文件系統(tǒng)任何位置智绸,只要Django可以訪問到就行。(Django可以用你服務(wù)器上的任何用戶來運行)访忿,但是瞧栗,保證模板在你的項目里,是一個指的遵守的良好規(guī)則海铆。
打開你的設(shè)置文件(mysite/settings.py沼溜,記住)然后添加一個DIRS選項到TEMPLATES設(shè)置里:

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是一個在加載Django模板時候需要檢查的文件系統(tǒng)目錄列表游添,它是一個搜索路徑系草。

組織模板

和靜態(tài)文件相似,我們可以吧所有的模板都放到一起唆涝,在一個大的模板目錄里找都。并且它也可以很好地工作。但是廊酣,屬于特定應(yīng)用的模板應(yīng)該位于這個應(yīng)用自己的模板目錄里(例如polls/templates)而不是在項目的模板目錄里(templates)能耻。我們會在重復(fù)使用app教程里討論我們?yōu)槭裁匆@樣做。

現(xiàn)在在templates里面創(chuàng)建一個叫做admin的目錄亡驰,然后在Django它自己的(django/contrib/admin/templates)的源代碼的Django默認管理模板目錄里復(fù)制admin/base_site.html模板到admin目錄下面晓猛。

Django源文件在哪?

如果在你的系統(tǒng)上查找Django源文件比較困難凡辱,運行下面的命令:

$ python -c "import django; 
print(django.__path__)"

然后編輯base_site.html文件戒职,將{{ site_header|default:_('Django administration') }} (包括正確的括號)替換為你自己的站點名稱。最后你的代碼必須像下面這樣:

{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}

我們用這種方式告訴你怎么覆蓋模板透乾,在一個實際的項目里洪燥,你可能會使用django.contrib.admin.AdminSite.site_header屬性,來更簡單地完成特定的定制乳乌。

這個模板文件包含大量像{% block branding %}和{{ title }}這樣的文本捧韵。{% 和 {{ 標簽是Django模板語言的一部分。當(dāng)django渲染admin/base_site.html的時候汉操,這個模板語言會被鑒定并生成最終的HTML頁面再来,就像我們在第三節(jié)里看的那樣。

要注意磷瘤,任何Django的默認管理模板都能被覆蓋芒篷,要覆蓋一個模板搜变,只需要像你在base_site.html里做的那樣。把它從默認目錄里復(fù)制出來梭伐,放到你的定制目錄里去,然后做修改仰担。

定制你的應(yīng)用的模板

精明的讀者可能會問:如果默認情況下DIRS是空的糊识,Django怎么找到默認的管理頁面?回答是摔蓝,只要APP_DIRS設(shè)置為True赂苗,Django會自動在每一個應(yīng)用包里找templates子目錄,作為一個返回值使用(不要忘了django.contrib.admin是一個應(yīng)用)贮尉。

我們的投票應(yīng)用不是非常復(fù)雜拌滋,并且不需要定制admin 模板,但是如果它成長得更加復(fù)雜猜谚,為了實現(xiàn)它的一些功能败砂,需要修改Django的標準管理模板。直接修改應(yīng)用的模板比修改項目的模板更明智魏铅。通過這種方式昌犹,你可以再任何心的項目里包含投票應(yīng)用,并且保證它能夠找到自己定制后的模板览芳。

Django怎么查找它的模板的更多細節(jié)斜姥,請查看模板加載文檔

定制管理首頁

在一些類似的說明中沧竟,你可能會想定制Django管理首頁的外觀和感覺铸敏。
默認情況下,它用字母排序來顯示所有在INSTALLED_APPS里悟泵,且使用admin應(yīng)用注冊了的應(yīng)用杈笔。你可能想對布局進行大的修改,畢竟糕非,首頁可能是管理頁面里最重要的頁面桩撮,它應(yīng)該易于使用。

需要定制的模板是admin/index.html(和前面部分里對admin/base_site.html做的一樣— 把它從默認的目錄里復(fù)制到你的定制模板目錄里)峰弹。編輯這個文件店量,然后你會看到它使用一個叫做app_list的模板變量,這個變量包含每個安裝了的Django app鞠呈。為了替換這個融师,你可以使用硬編碼的鏈接指到特定對象的管理頁面,用你自己覺得最好的方式來做蚁吝。

下一步做什么旱爆?

教程的初始部分到這就結(jié)束了舀射,與此同時,你可能想在where to go from here里看到一些提示怀伦。

如果你對Python打包很熟悉脆烟,且對學(xué)習(xí)怎么把投票應(yīng)用轉(zhuǎn)變?yōu)橐粋€可重復(fù)使用的app非常感興趣,可以看高級教程:怎么寫重復(fù)使用的app房待。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末邢羔,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子桑孩,更是在濱河造成了極大的恐慌拜鹤,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,907評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件流椒,死亡現(xiàn)場離奇詭異敏簿,居然都是意外死亡,警方通過查閱死者的電腦和手機宣虾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評論 3 395
  • 文/潘曉璐 我一進店門惯裕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人绣硝,你說我怎么就攤上這事轻猖。” “怎么了域那?”我有些...
    開封第一講書人閱讀 164,298評論 0 354
  • 文/不壞的土叔 我叫張陵咙边,是天一觀的道長。 經(jīng)常有香客問我次员,道長败许,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,586評論 1 293
  • 正文 為了忘掉前任淑蔚,我火速辦了婚禮市殷,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘刹衫。我一直安慰自己醋寝,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,633評論 6 392
  • 文/花漫 我一把揭開白布带迟。 她就那樣靜靜地躺著音羞,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仓犬。 梳的紋絲不亂的頭發(fā)上嗅绰,一...
    開封第一講書人閱讀 51,488評論 1 302
  • 那天,我揣著相機與錄音,去河邊找鬼窘面。 笑死翠语,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的财边。 我是一名探鬼主播肌括,決...
    沈念sama閱讀 40,275評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼酣难!你這毒婦竟也來了谍夭?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,176評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鲸鹦,失蹤者是張志新(化名)和其女友劉穎慧库,沒想到半個月后跷跪,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體馋嗜,經(jīng)...
    沈念sama閱讀 45,619評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,819評論 3 336
  • 正文 我和宋清朗相戀三年吵瞻,在試婚紗的時候發(fā)現(xiàn)自己被綠了葛菇。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,932評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡橡羞,死狀恐怖眯停,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情卿泽,我是刑警寧澤莺债,帶...
    沈念sama閱讀 35,655評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站签夭,受9級特大地震影響齐邦,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜第租,卻給世界環(huán)境...
    茶點故事閱讀 41,265評論 3 329
  • 文/蒙蒙 一措拇、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧慎宾,春花似錦丐吓、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,871評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至汹碱,卻和暖如春族操,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,994評論 1 269
  • 我被黑心中介騙來泰國打工色难, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留泼舱,地道東北人。 一個月前我還...
    沈念sama閱讀 48,095評論 3 370
  • 正文 我出身青樓枷莉,卻偏偏與公主長得像娇昙,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子笤妙,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,884評論 2 354

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