Django 官網(wǎng)最新 Tutorial 渣翻 - Part 7

上一節(jié):Django 官網(wǎng)最新 Tutorial 渣翻 - Part 6

本教程上接Tutorial 6 稀蟋。 我們繼續(xù)網(wǎng)頁投票應(yīng)用,并將重點(diǎn)定制Django自動生成的管理后臺站點(diǎn)骏融,這是我們在Tutorial 2中首先探討的。

自定義管理后臺的表單

只需使用admin.site.register(Question)注冊Question模型档玻,Django就能構(gòu)造一個默認(rèn)的表單表示茫藏。 通常境钟,你會想要自定義管理界面中表單的外觀和功能匣缘。 你可以通過在注冊對象的時(shí)候告知Django一些你想要的選項(xiàng)來完成。

讓我們看看如何通過重新排序編輯表單上的字段來實(shí)現(xiàn)。 將admin.site.register(Question)行替換成:

polls/admin.py

from django.contrib import admin

from .models import Question


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

admin.site.register(Question, QuestionAdmin)

任何時(shí)候你需要更改模型的管理選項(xiàng),你將遵循此模式 — 創(chuàng)建一個模型管理類,然后將其作為第二個參數(shù)傳遞給admin.site.register()泊窘。

上面那特定的更改,使得“Publication date”字段排在“Question”字段前面:

僅有兩個字段不會令你印象深刻瓜贾,但是當(dāng)管理有許多字段的表單時(shí),選擇一個直觀的排序方式是一個重要而實(shí)用的細(xì)節(jié)祭芦。

說到有許多字段的表單憔鬼,你可能想把表單分割成字段集:

polls/admin.py

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)

fieldsets中每個元組的第一個元素是字段集的標(biāo)題龟劲。 以下是我們的對象表單現(xiàn)在的樣子:


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

好的轴或,我們有我們的Question管理頁面,但Question有多個Choice蚕愤,而管理頁面沒有顯示Choice。

然鵝

有兩種方法來解決這個問題萍诱。 第一種是像我們?yōu)镼uestion做的一樣污呼,在管理站點(diǎn)中注冊Choice裕坊。 這很簡單:

polls/admin.py

from django.contrib import admin

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

現(xiàn)在燕酷,可以在Django管理站點(diǎn)中管理“Choices”。 “Add choice”表單看起來像這樣:

在這個表單中苗缩,“Question”字段是一個可選的選項(xiàng)框,包含數(shù)據(jù)庫中所有的Question苹享。 Django中一個ForeignKey應(yīng)該在管理界面中顯示為一個<select>選框。 在我們的例子中得问,目前選框里只有一個Question。

另請注意“Question”旁邊的“Add Another”鏈接宫纬。具有ForeignKey關(guān)系的每個對象都默認(rèn)有一個這樣的鏈接。 當(dāng)你點(diǎn)擊“Add Another”時(shí)漓骚,你將看到一個帶有“Add question”表單的彈出窗口。 如果你在該窗口中添加了一個Question并單擊“Save”蝌蹂,Django會將該Question保存到數(shù)據(jù)庫中,并將其作為選定的選項(xiàng)動態(tài)添加到你正在查看的“Add choice”表單中剃允。

但事實(shí)上,這不是一種高效的方式來添加Choice對象到系統(tǒng)中斥废。 在創(chuàng)建Question對象的同時(shí)可以直接添加一組Choice將會更好给郊。 讓我們實(shí)現(xiàn)這個功能牡肉。

移除對Choice模型的register()調(diào)用淆九。 然后將Question的注冊代碼編輯為:

polls/admin.py

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:“Choice對象在Question的管理界面中編輯。 默認(rèn)提供3個Choice跪另∨《叮”

打開“Add question”頁面:


它這樣工作:有三個所關(guān)聯(lián)的Choice —— 由extra指定 —— 每次你回到已經(jīng)存在對象的"Change"頁面時(shí),都會額外地獲得三個空白Choice擦盾。

在現(xiàn)有的三個Choice的底部淌哟,你會發(fā)現(xiàn)一個“Add another Choice”的鏈接迹卢。 如果你點(diǎn)擊它徒仓,就會增加一個新的空白Choice。 如果你想移除一個新增加的空白Choice,可以點(diǎn)擊其右上角的X症见。 請注意,你無法移除那最初的三個空白Choice芋肠。 下面的圖片展示新增加的一個空白Choice:

還有個小問題遵蚜。 顯示所有關(guān)聯(lián)的Choice 對象的字段占用大量的屏幕空間帖池。 為此吭净,Django提供了一種顯示內(nèi)聯(lián)相關(guān)對象的表格方式;你只需將ChoiceInline聲明更改為:

polls/admin.py

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

使用TabularInline(而不是StackedInline)寂殉,這些相關(guān)聯(lián)的對象顯示成緊湊的、基于表格的形式:


你有沒有注意有一個額外的列“Delete?”文兢,用“Add Another Choice”按鈕添加的行和已經(jīng)保存的行可以通過它來刪除。


自定義admin change列表

現(xiàn)在姆坚,Question管理界面看起來已經(jīng)很好了实愚,讓我們再來稍微調(diào)整一下“變更列表”界面 —— 該界面顯示系統(tǒng)中所有的Question兼呵。

下面是目前為止它的樣子:


默認(rèn)地腊敲,Django顯示每個對象的str()返回的內(nèi)容。 但有時(shí)如果我們能顯示個別的字段將很有幫助碰辅。 我們使用list_display選項(xiàng)來實(shí)現(xiàn)這個功能,它是一個要顯示的字段名稱的元組凌彬,在對象的變更列表頁面上作為列顯示:

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

為了方便查看,我們還添加了Tutorial 2中的was_published_recently()方法:

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

現(xiàn)在铲敛,Question變更列表頁面看起來就像如下所示:


你可以點(diǎn)擊其中一列的頭部來讓列表按照這列的值來進(jìn)行排序 —— 除了was_published_recently這列的頭部会钝,因?yàn)镈jango不支持按照隨便一個方法的輸出進(jìn)行排序。 另請注意,默認(rèn)情況下先鱼,was_published_recently的列標(biāo)題是方法的名稱(下劃線替換為空格),每行包含輸出的字符串表示形式段审。

通過給這個方法(在polls/models.py)提供一些屬性改進(jìn),如下所示:

polls/models.py

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文件來改進(jìn)Question變更列表頁面:使用 list_filter來添加過濾器寺枉。 將下面這行添加進(jìn)QuestionAdmin

polls/admin.py
class Question(models.Model):
    ...
    list_filter = ['pub_date']

這行代碼添加一個“Filter”側(cè)邊欄绷落,可以使人們通過pub_date字段對變更列表進(jìn)行過濾:

顯示的過濾器類型取決于你所使用的字段類型。 因?yàn)?code>pub_date是一個 DateTimeField砌烁,Django知道提供適當(dāng)?shù)倪^濾器選項(xiàng):“任何日期”,“今天”函喉,“過去7天”,“這個月”管呵,“這年”。

這樣看起來有些像我們想要的樣子了账锹。 讓我們再來添加一些搜索功能:

search_fields = ['question_text']

這行代碼在變更列表的頂部添加了一個搜索框。 當(dāng)有人將搜索的內(nèi)容輸入搜索框坷襟,Django將在question_text字段中進(jìn)行搜索。 你可以使用任意數(shù)量的字段進(jìn)行搜索 —— 但由于它在后臺使用LIKE進(jìn)行查詢廓奕,所以限制搜索字段的數(shù)量會使數(shù)據(jù)庫查詢更加容易。

現(xiàn)在又是一個好時(shí)機(jī)來告訴你變更列表界面提供方便的分頁功能懂从。 默認(rèn)每頁顯示100條記錄蹲蒲。 Change listpagination, search boxes, filters, date-hierarchies, 和 column-header-ordering 都將按照你設(shè)想的那樣工作。


定制管理后臺的外觀

很明顯届搁,每個管理頁面的頂部都有“Django administration”不太合適。 它僅僅起到了占位符的作用卡睦。

它可以用Django的模板系統(tǒng)輕松改變。 Django的管理站點(diǎn)是用Django自己制作出來的表锻,它的界面代碼使用的是Django自己的模板系統(tǒng)。

定制項(xiàng)目的模板

在你項(xiàng)目的文件夾內(nèi)(包含 manage.py的目錄)創(chuàng)建一個templates目錄瞬逊。 Templates可以放在你的文件系統(tǒng)中的任何地方, 只要Django所能訪問到。(運(yùn)行Web服務(wù)器的用戶即是運(yùn)行Django的用戶)确镊。 然而,把模板放在項(xiàng)目目錄下會是一個值得提倡的蕾域、應(yīng)該遵循的約定。

打開你的配置文件(記住是mysite/settings.py)在 TEMPLATESsettings中添加一個 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是加載Django模板時(shí)要檢查的文件系統(tǒng)目錄的列表巨缘;它是一個搜索路徑采呐。

安排模塊結(jié)構(gòu)
就像靜態(tài)文件一樣带猴,我們可以將所有的模板都放在一個大的模板目錄中懈万,并且工作得很好。但是会通,屬于特定應(yīng)用程序的模板應(yīng)該放在該應(yīng)用程序的模板目錄中(例如polls/templates)而不是項(xiàng)目的(templates)。 我們將在 reusable apps tutorial 中更詳細(xì)地討論為什么我們這樣做涕侈。

現(xiàn)在,在templates下創(chuàng)建一個名為admin的文件夾裳涛,然后從Django安裝的原目錄下(目錄為django/contrib/admin/templates)將模板頁面的源文件admin/base_site.html拷貝到這個文件夾里。

Django的源文件在哪里舷礼?
如果你找不到Django源文件在你系統(tǒng)上的位置,運(yùn)行如下命令:
python -c "import django; print(django.__path__)"

然后妻献,只需編輯該文件并替換{{ site_header|default:_('Django administration') }}(包括花括號)為你認(rèn)為合適的自己站點(diǎn)的名稱。 編輯完成后應(yīng)該類似下面的代碼片段:

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

我們使用這個例子來教你如何覆蓋模板育拨。在實(shí)際項(xiàng)目中,你可能會使用 django.contrib.admin.AdminSite.site_header 屬性來更簡單地實(shí)現(xiàn)這個自定義功能熬丧。

模板文件包含許多類似{% block branding %}{{ title }}這樣的文本。 {{{% 是Django模板語言的一部分析蝴。 當(dāng)Django呈現(xiàn)admin/base_site.html時(shí),將會評估此模板語言以生成最終的HTML頁面嫌变,就像我們在Tutorial 3看到的那樣。

注意任何Django管理站點(diǎn)的默認(rèn)模板都可以被覆蓋腾啥。 想要覆蓋一個模板文件,只需要做和覆蓋base_site.html相同的操作就行 —— 將它從默認(rèn)的目錄拷貝到你自定義的目錄中疮跑,然后修改它。


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

See the template loading documentation for more information about how Django finds its templates.

細(xì)心的讀者將會問:由于DIRS默認(rèn)是空的祖娘,Django是怎么找到默認(rèn)的管理站點(diǎn)模板的啊奄? 答案是渐苏,由于 APP_DIRS設(shè)置為True菇夸,Django會自動地在每個應(yīng)用包下面查找一個templates/子目錄,留作備用庄新。(別忘了,django.contrib.admin 也是一個應(yīng)用)择诈。

我們的投票應(yīng)用并不是太復(fù)雜,不需要自定義管理站點(diǎn)模板羞芍。 但是如果它變得更加復(fù)雜而且為了一些功能需要修改Django的標(biāo)準(zhǔn)管理站點(diǎn)模板,那么與修改項(xiàng)目中的模板相比涩金,修改應(yīng)用中的模板將是更明智的選擇暇仲。 使用這種方式副渴,你可以在任何新項(xiàng)目中使用投票應(yīng)用,并且可以確保Django將找到它需要的自定義模板文件煮剧。

更多關(guān)于Django如何找到它的模板文件的信息将鸵,請查看 template loading documentation勉盅。


自定義管理后臺的主頁

與上面類似的是顶掉,你可能想自定義Django管理站點(diǎn)首頁面的外觀。

默認(rèn)情況下痒筒,首頁面顯示所有位于 INSTALLED_APPS 中且已經(jīng)使用管理站點(diǎn)應(yīng)用注冊過的應(yīng)用,這些應(yīng)用按照字母順序進(jìn)行顯示簿透。 你可能想在布局上做出重大改變。 畢竟葡盗,首頁面可能是管理站點(diǎn)中最重要的頁面,并且它應(yīng)當(dāng)易用觅够。

需要自定義的模板文件是 admin/index.html巷嚣。 (與上一節(jié)中的admin/base_site.html相同 - 將其從默認(rèn)目錄復(fù)制到您的自定義模板目錄)蔚约。 編輯這個文件涂籽,你將看到它有一個叫做app_list的變量。 這個變量包含安裝的所有Django應(yīng)用评雌。 你可以選擇不像默認(rèn)模板中那樣使用它树枫,而是以你認(rèn)為最好的方式硬編碼鏈接到每個對象自己的管理頁面。

接下來是什么景东?

初學(xué)者教程結(jié)束于此砂轻。 在這期間,你可能想要在where to go from here中了解文檔的結(jié)構(gòu)和查找相關(guān)信息方法斤吐。

如果你熟悉Python 打包的技術(shù)搔涝,并且對如何將投票應(yīng)用制作成一個“可重用的應(yīng)用”感興趣厨喂,請看 Advanced tutorial: How to write reusable apps.

下一節(jié):Django 官網(wǎng)最新 Tutorial 渣翻 - Part 8(進(jìn)階教程)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市庄呈,隨后出現(xiàn)的幾起案子蜕煌,更是在濱河造成了極大的恐慌,老刑警劉巖诬留,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件斜纪,死亡現(xiàn)場離奇詭異,居然都是意外死亡文兑,警方通過查閱死者的電腦和手機(jī)盒刚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門绿贞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來因块,“玉大人,你說我怎么就攤上這事籍铁∥猩希” “怎么了?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵寨辩,是天一觀的道長吓懈。 經(jīng)常有香客問我,道長靡狞,這世上最難降的妖魔是什么耻警? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮甸怕,結(jié)果婚禮上甘穿,老公的妹妹穿的比我還像新娘。我一直安慰自己梢杭,他們只是感情好温兼,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著武契,像睡著了一般募判。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上咒唆,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天届垫,我揣著相機(jī)與錄音,去河邊找鬼全释。 笑死装处,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的浸船。 我是一名探鬼主播妄迁,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼寝蹈,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了登淘?” 一聲冷哼從身側(cè)響起箫老,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎形帮,沒想到半個月后槽惫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體周叮,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡辩撑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了仿耽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片合冀。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖项贺,靈堂內(nèi)的尸體忽然破棺而出君躺,到底是詐尸還是另有隱情,我是刑警寧澤开缎,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布棕叫,位于F島的核電站,受9級特大地震影響奕删,放射性物質(zhì)發(fā)生泄漏俺泣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一完残、第九天 我趴在偏房一處隱蔽的房頂上張望伏钠。 院中可真熱鬧,春花似錦谨设、人聲如沸熟掂。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赴肚。三九已至,卻和暖如春二蓝,著一層夾襖步出監(jiān)牢的瞬間誉券,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工侣夷, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留横朋,地道東北人。 一個月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓百拓,卻偏偏與公主長得像琴锭,于是被迫代替她去往敵國和親晰甚。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348

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