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

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

本教程上接Tutorial 6 。 我們繼續(xù)網(wǎng)頁投票應(yīng)用,并將重點(diǎn)定制Django自動(dòng)生成的管理后臺(tái)站點(diǎn),這是我們?cè)?a target="_blank" rel="nofollow">Tutorial 2中首先探討的。

自定義管理后臺(tái)的表單

只需使用admin.site.register(Question)注冊(cè)Question模型,Django就能構(gòu)造一個(gè)默認(rèn)的表單表示。 通常,你會(huì)想要自定義管理界面中表單的外觀和功能。 你可以通過在注冊(cè)對(duì)象的時(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)建一個(gè)模型管理類,然后將其作為第二個(gè)參數(shù)傳遞給admin.site.register()。

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

僅有兩個(gè)字段不會(huì)令你印象深刻,但是當(dāng)管理有許多字段的表單時(shí),選擇一個(gè)直觀的排序方式是一個(gè)重要而實(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中每個(gè)元組的第一個(gè)元素是字段集的標(biāo)題。 以下是我們的對(duì)象表單現(xiàn)在的樣子:


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

好的,我們有我們的Question管理頁面,但Question有多個(gè)Choice,而管理頁面沒有顯示Choice。

然鵝

有兩種方法來解決這個(gè)問題。 第一種是像我們?yōu)镼uestion做的一樣,在管理站點(diǎn)中注冊(cè)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”表單看起來像這樣:

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

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

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

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

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對(duì)象在Question的管理界面中編輯。 默認(rèn)提供3個(gè)Choice。”

打開“Add question”頁面:


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

在現(xiàn)有的三個(gè)Choice的底部,你會(huì)發(fā)現(xiàn)一個(gè)“Add another Choice”的鏈接。 如果你點(diǎn)擊它,就會(huì)增加一個(gè)新的空白Choice。 如果你想移除一個(gè)新增加的空白Choice,可以點(diǎn)擊其右上角的X。 請(qǐng)注意,你無法移除那最初的三個(gè)空白Choice。 下面的圖片展示新增加的一個(gè)空白Choice:

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

polls/admin.py

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

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


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


自定義admin change列表

現(xiàn)在,Question管理界面看起來已經(jīng)很好了,讓我們?cè)賮砩晕⒄{(diào)整一下“變更列表”界面 —— 該界面顯示系統(tǒng)中所有的Question。

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


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

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不支持按照隨便一個(gè)方法的輸出進(jìn)行排序。 另請(qǐng)注意,默認(rèn)情況下,was_published_recently的列標(biāo)題是方法的名稱(下劃線替換為空格),每行包含輸出的字符串表示形式。

通過給這個(gè)方法(在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']

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

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

這樣看起來有些像我們想要的樣子了。 讓我們?cè)賮硖砑右恍┧阉鞴δ埽?/p>

search_fields = ['question_text']

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

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


定制管理后臺(tái)的外觀

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

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

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

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

打開你的配置文件(記住是mysite/settings.py)在 TEMPLATESsettings中添加一個(gè) 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)目錄的列表;它是一個(gè)搜索路徑。

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

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

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

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

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

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

模板文件包含許多類似{% block branding %}{{ title }}這樣的文本。 {{{% 是Django模板語言的一部分。 當(dāng)Django呈現(xiàn)admin/base_site.html時(shí),將會(huì)評(píng)估此模板語言以生成最終的HTML頁面,就像我們?cè)?a target="_blank" rel="nofollow">Tutorial 3看到的那樣。

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


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

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

細(xì)心的讀者將會(huì)問:由于DIRS默認(rèn)是空的,Django是怎么找到默認(rèn)的管理站點(diǎn)模板的? 答案是,由于 APP_DIRS設(shè)置為True,Django會(huì)自動(dòng)地在每個(gè)應(yīng)用包下面查找一個(gè)templates/子目錄,留作備用。(別忘了,django.contrib.admin 也是一個(gè)應(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如何找到它的模板文件的信息,請(qǐng)查看 template loading documentation。


自定義管理后臺(tái)的主頁

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

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

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

接下來是什么?

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

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

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容