Django4.0 開始-編寫你的第一個(gè)Django應(yīng)用,第7部分

2022-09-03 09:34 更新

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

通過 ?admin.site.register(Question)? 注冊(cè) ?Question ?模型,Django 能夠構(gòu)建一個(gè)默認(rèn)的表單用于展示。通常來說,你期望能自定義表單的外觀和工作方式。你可以在注冊(cè)模型時(shí)將這些設(shè)置告訴 Django。
讓我們通過重排列表單上的字段來看看它是怎么工作的。用以下內(nèi)容替換 ?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)

你需要遵循以下流程——?jiǎng)?chuàng)建一個(gè)模型后臺(tái)類,接著將其作為第二個(gè)參數(shù)傳給 ?admin.site.register() ?——在你需要修改模型的后臺(tái)管理選項(xiàng)時(shí)這么做。
以上修改使得 "Publication date" 字段顯示在 "Question" 字段之前:

admin07


只有兩個(gè)字段并不令人印象深刻,但對(duì)于具有數(shù)十個(gè)字段的管理表單,選擇直觀的順序是一個(gè)重要的可用性細(xì)節(jié)。

說到具有數(shù)十個(gè)字段的表單,您可能希望將表單拆分為字段集:

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è)元素是字段集的標(biāo)題。以下是我們的表單現(xiàn)在的樣子:

admin08t

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

好了,現(xiàn)在我們有了投票的后臺(tái)頁。不過,一個(gè) ?Question ?有多個(gè) ?Choice?,但后臺(tái)頁卻沒有顯示多個(gè)選項(xiàng)。
有兩個(gè)方法可以解決這個(gè)問題。第一個(gè)就是仿照我們向后臺(tái)注冊(cè) ?Question ?一樣注冊(cè) ?Choice ?:

from django.contrib import admin

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

現(xiàn)在 "Choices" 在 Django 后臺(tái)頁中是一個(gè)可用的選項(xiàng)了。“添加選項(xiàng)”的表單看起來像這樣:

admin09

在這個(gè)表單中,"Question" 字段是一個(gè)包含數(shù)據(jù)庫中所有投票的選擇框。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ù)庫,并動(dòng)態(tài)地在你正在查看的“添加選項(xiàng)”表單中選中它。

不過,這是一種很低效地添加“選項(xiàng)”的方法。更好的辦法是在你創(chuàng)建“投票”對(duì)象時(shí)直接添加好幾個(gè)選項(xiàng)。讓我們實(shí)現(xiàn)它。
移除調(diào)用 ?register()? 注冊(cè) ?Choice ?模型的代碼。隨后,像這樣修改 ?Question ?的注冊(cè)代碼:

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)

這會(huì)告訴 Django:“?Choice ?對(duì)象要在 ?Question ?后臺(tái)頁面編輯。默認(rèn)提供 3 個(gè)足夠的選項(xiàng)字段?!?br>加載“添加投票”頁面來看看它長啥樣:

admin10t

它看起來像這樣:有三個(gè)關(guān)聯(lián)的選項(xiàng)插槽——由 ?extra ?定義,且每次你返回任意已創(chuàng)建的對(duì)象的“修改”頁面時(shí),你會(huì)見到三個(gè)新的插槽。
在三個(gè)插槽的末端,你會(huì)看到一個(gè)“添加新選項(xiàng)”的按鈕。如果你單擊它,一個(gè)新的插槽會(huì)被添加。如果你想移除已有的插槽,可以點(diǎn)擊插槽右上角的X。以下圖片展示了一個(gè)已添加的插槽:

admin14t

不過,仍然有點(diǎn)小問題。它占據(jù)了大量的屏幕區(qū)域來顯示所有關(guān)聯(lián)的 ?Choice ?對(duì)象的字段。對(duì)于這個(gè)問題,Django 提供了一種表格式的單行顯示關(guān)聯(lián)對(duì)象的方法。要使用它,只需按如下形式修改 ?ChoiceInline ?申明:

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

通過 ?TabularInline ?(替代 ?StackedInline ?),關(guān)聯(lián)對(duì)象以一種表格式的方式展示,顯得更加緊湊:

admin11t

注意這里有一個(gè)額外的“刪除”列,這允許移除通過“添加新選項(xiàng)”按鈕添加的,或是已被保存的行。

自定義后臺(tái)更改列表

現(xiàn)在投票的后臺(tái)頁看起來很不錯(cuò),讓我們對(duì)“更改列表”頁面進(jìn)行一些調(diào)整——改成一個(gè)能展示系統(tǒng)中所有投票的頁面。

以下是它此時(shí)的外觀:

admin04t (1)

默認(rèn)情況下,Django 顯示每個(gè)對(duì)象的 ?str()? 返回的值。但有時(shí)如果我們能夠顯示單個(gè)字段,它會(huì)更有幫助。為此,使用 ?list_display ?后臺(tái)選項(xiàng),它是一個(gè)包含要顯示的字段名的元組,在更改列表頁中以列的形式展示這個(gè)對(duì)象:

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

另外,讓我們把 教程第 2 部分 中的 ?was_published_recently()? 方法也加上:

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

現(xiàn)在修改投票的列表頁看起來像這樣:

admin12t

你可以點(diǎn)擊列標(biāo)題來對(duì)這些行進(jìn)行排序——除了 ?was_published_recently ?這個(gè)列,因?yàn)闆]有實(shí)現(xiàn)排序方法。順便看下這個(gè)列的標(biāo)題 ?was_published_recently?,默認(rèn)就是方法名(用空格替換下劃線),該列的每行都以字符串形式展示出處。
你可以通過在該方法上(在 ?polls/models.py? 中)使用 ?display()? 裝飾器來改進(jìn),如下圖所示:

from django.contrib import admin

class Question(models.Model):
    # ...
    @admin.display(
        boolean=True,
        ordering='pub_date',
        description='Published recently?',
    )
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now

再次編輯文件 ?polls/admin.py?,優(yōu)化 ?Question變更頁:過濾器,使用 ?list_filter?。將以下代碼添加至 ?QuestionAdmin?:

list_filter = ['pub_date']

這樣做添加了一個(gè)“過濾器”側(cè)邊欄,允許人們以 ?pub_date ?字段來過濾列表:

admin13t

展示的過濾器類型取決你你要過濾的字段的類型。因?yàn)??pub_date ?是類 ?DateTimeField?,Django 知道要提供哪個(gè)過濾器:“任意時(shí)間”,“今天”,“過去7天”,“這個(gè)月”和“今年”。
這已經(jīng)弄的很好了。讓我們?cè)贁U(kuò)充些功能:

search_fields = ['question_text']

在列表的頂部增加一個(gè)搜索框。當(dāng)輸入待搜項(xiàng)時(shí),?Django ?將搜索 ?question_text ?字段。你可以使用任意多的字段——由于后臺(tái)使用 ?LIKE ?來查詢數(shù)據(jù),將待搜索的字段數(shù)限制為一個(gè)不會(huì)出問題大小,會(huì)便于數(shù)據(jù)庫進(jìn)行查詢操作。
現(xiàn)在是給你的修改列表頁增加分頁功能的好時(shí)機(jī)。默認(rèn)每頁顯示 100 項(xiàng)。變更頁分頁, 搜索框, 過濾器, 日期層次結(jié)構(gòu), 和 列標(biāo)題排序 均以你期望的方式合作運(yùn)行。

自定義后臺(tái)界面和風(fēng)格

在每個(gè)后臺(tái)頁頂部顯示“Django 管理員”顯得很滑稽。這只是一串占位文本。
不過,你可以通過 Django 的模板系統(tǒng)來修改。Django 的后臺(tái)由自己驅(qū)動(dòng),且它的交互接口采用 Django 自己的模板系統(tǒng)。

自定義你的工程模板

在你的工程目錄(指包含 ?manage.py? 的那個(gè)文件夾)內(nèi)創(chuàng)建一個(gè)名為 ?templates ?的目錄。模板可放在你系統(tǒng)中任何 Django 能找到的位置。(誰啟動(dòng)了 Django,Django 就以他的用戶身份運(yùn)行。)不過,把你的模板放在工程內(nèi)會(huì)帶來很大便利,推薦你這樣做。
打開你的設(shè)置文件(?mysite/settings.py?,牢記),在 ?TEMPLATES ?設(shè)置中添加 ?DIRS ?選項(xiàng):

?DIRS ?中只需填寫模板路徑即可

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [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è)待搜索路徑。

現(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)。

接著,用你網(wǎng)頁站點(diǎn)的名字編輯替換文件內(nèi)的 ?{{ site_header|default:_('Django administration') }}? (包含大括號(hào))。完成后,你應(yīng)該看到如下代碼:

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

我們會(huì)用這個(gè)方法來教你復(fù)寫模板。在一個(gè)實(shí)際工程中,你可能更期望使用 ?django.contrib.admin.AdminSite.site_header? 來進(jìn)行簡單的定制。
這個(gè)模板文件包含很多類似 ?{% block branding %}? 和 ?{{ title }}? 的文本。 ?{%? 和 ?{{? 標(biāo)簽是 Django 模板語言的一部分。當(dāng) Django 渲染 ?admin/base_site.html? 時(shí),這個(gè)模板語言會(huì)被求值,生成最終的網(wǎng)頁,就像我們?cè)?教程第 3 部分 所學(xué)的一樣。
注意,所有的 Django 默認(rèn)后臺(tái)模板均可被復(fù)寫。若要復(fù)寫模板,像你修改 ?base_site.html? 一樣修改其它文件——先將其從默認(rèn)目錄中拷貝到你的自定義目錄,再做修改。

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

機(jī)智的同學(xué)可能會(huì)問: ?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ù)雜,所以無需自定義后臺(tái)模板。不過,如果它變的更加復(fù)雜,需要修改 Django 的標(biāo)準(zhǔn)后臺(tái)模板功能時(shí),修改 應(yīng)用 的模板會(huì)比 工程 的更加明智。這樣,在其它工程包含這個(gè)投票應(yīng)用時(shí),可以確保它總是能找到需要的自定義模板文件。

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

在類似的說明中,你可能想要自定義 Django 后臺(tái)索引頁的外觀。
默認(rèn)情況下,它展示了所有配置在 ?INSTALLED_APPS ?中,已通過后臺(tái)應(yīng)用注冊(cè),按拼音排序的應(yīng)用。你可能想對(duì)這個(gè)頁面的布局做重大的修改。畢竟,索引頁是后臺(tái)的重要頁面,它應(yīng)該便于使用。
需要自定義的模板是 ?admin/index.html?。(像上一節(jié)修改 ?admin/base_site.html? 那樣修改此文件——從默認(rèn)目錄中拷貝此文件至自定義模板目錄)。打開此文件,你將看到它使用了一個(gè)叫做 ?app_list ?的模板變量。這個(gè)變量包含了每個(gè)安裝的 Django 應(yīng)用。你可以用任何你期望的硬編碼鏈接(鏈接至特定對(duì)象的管理頁)替代使用這個(gè)變量。


以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)