Django 2.0.1 官方文檔翻譯: 編寫你的第一個 Django app,第七部分(Page 12)

編寫你的第一個 Django app,第七部分(Page 12)轉載請註明連接地址

本節教程承接第六部分(page 11)的教程。咱們繼續開發 web-poll應用,並專一於自定義django的自動生成的admin站點,這點咱們在第二部分(page 7)中探討過。html

自定義admin表單

經過在admin.site.register(Question)中註冊Question模型,django能夠構建一個默認的表單形式。一般,你會但願自定義表單的外觀和工做方式。你會在註冊對象時告訴django你想使用的選項。python

咱們來看看編輯表單中的字段順序是如何工做的。使用下面的代碼替換admin.site.register(Question)web

# 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)

你會遵循這個模式 —— 建立一個admin類的模型,而後把它傳遞給admin.site.register()的第二個參數 —— 當你須要爲一個模型修改admin選項時。shell

上面的更改使「Publication date」字段出如今「Question」字段以前:數據庫

這裏僅有兩個字段,給人的印象不夠深入,但對於有幾十個字段的admin表單來講,選擇一個有直觀順序則是一個有重要做用的細節。django

說到有幾十個字段的表單,有可能會想把表單分割成字段集合:服務器

# 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中每一個元組的第一個元素是字段集合的標題。這是咱們的表單如今的外觀:app

添加關聯對象

如今咱們有了Question管理頁面,可是一個Question有多個Choice,而且管理頁面不顯示choice。佈局

然而,有兩種方式解決這個問題。第一種是在admin中註冊choice,就像咱們以前對Question作的同樣。這很簡單:編碼

# polls/admin.py
from django.contrib import admin

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

如今在django 的admin中 「Choices」 是有一個有效的選項。 「Add choice」表單就像下面的樣子:

在這個表單中, 「Question」 字段是一個包含數據庫中的各個問題的選擇框。django知道 ForeignKey(這裏少一個連接)對應admin中的<select>框。在咱們的例子中,此時只有一個quesiton存在。

同時要注意連接到下一個」Question「的 「Add Another」連接。每一個和其餘對象有ForeignKey(這裏少一個連接)關係的對象都有這個功能。當你點擊了「Add Another」,會出現一個有「Add Another」表單的彈出窗口。若是你在這個窗口中添加一個question並點擊「Save」,Django會把這個question保存到數據庫,並把它做爲一個可選擇的choice,動態添加它到你看到的「Add choice」表單中。

可是,實際上,這是一種向系統中添加Choice對象的很低效的方式。更好的方法是,在你建立Question對象的時,直接添加許多Choice。讓滿五年來實現它。

Choice模型中移除register()調用。而後,編輯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管理頁面被編輯。默認,爲3個choice提供足夠的字段。」

加載「Add question」頁面,看看它如今是什麼樣子:

它的工做方式是這樣的:有三個有聯繫的Choice —— 由extra指定 —— 而且每次你回到一個已建立對象的 「Change」 頁面,你都會獲得三個空白的Choice。

在當前三個Choice的底部,你會看到一個 「Add another Choice」 連接。若是你點擊了它,會添加一個新的Choices。若是你想一出一個已添加的Choice,你能夠在已添加的Choice中的右上角點擊 X。注意,你沒法移除最開始的三個Choice。這張圖展現了一個添加的Choice:

還有一個小問題,爲了顯示關聯的Choice對象,大量的屏幕空間用來顯示全部的字段。由於這個緣由,Django提供了以表格的形式顯示內嵌關係的對象;你只須要修改ChoiceInline的聲明便可:

# polls/admin.py
class ChoiceInline(admin.TabularInline):
    #...

使用TabularInline(替代了StackedInline),關聯的對象顯示成更緊湊的、基於表格的格式:

注意有一個額外的「Delete」列,它能夠移除使用「Add Another Choice」按鈕添加並保存的行。

自定義admin變動列表

如今問題管理頁面看起來看好,咱們在對「change list」頁面作一些小改動 —— 該頁面顯示系統中的全部Quesiton。

下面是它如今的樣子

默認狀況下,Django顯示每一個對象的str()。但有時候,若是咱們顯示單個字段會更有幫助。要實現這個功能,可使用list_display(這裏少一個連接)管理選項,它是一個字段名的元組,在change list頁面像列同樣顯示:

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

只是爲了更好一些,咱們把第二節中的was_published_recently()也加入進來:

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

如今問題change list 頁面看起來會像下面:

你能夠點擊列的頭部來以這個值來排序 —— 除了本例中was_published_recently的頭部,由於不支持以隨意一個方法的輸出來排序。另外要注意的是was_published_recently列的頭部默認是方法的名字(下劃線替換成空格),每行包行輸出的字符串形式。

你能夠經過給方法添加一些屬性來解決這個問題,以下:

# 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?'

更多關於這些方法屬性的信息,請查看list_display(這裏少一個連接)

再次編輯polls/admin.py文件,對Question change list頁面作一個改進:使用list_filter(這裏少一個連接)添加過濾器。把下面的行添加到QuestionAdmin中:

list_filter = ['pub_date']

這樣就添加了一「Filter」側邊欄,可讓人經過pub_date字段對change list進行過濾:

過濾器的顯示類型依賴於你使用的過濾字段的類型。由於pub_date是一個DateTimeField(這裏少一個連接),django會給出合適的過濾選項: 「Any date」, 「Today」, 「Past 7 days」, 「This month」, 「This year」.

如今一切進展順利。咱們添加一些搜索功能:

search_fields = ['question_text']

這樣會在change list頂部添加一個搜索框。當有人輸入搜索內容,django會搜索question_text字段。你能夠許多你喜歡的字段 —— 雖然它在後臺使用一個LIKE查詢,將搜索字段的數量限制爲合理的數目,會讓你的數據庫在搜索時更容易。

如今仍是一個告訴你change list提供方便的分頁功能的好機會。默認每頁顯示100項。 Change list pagination(這裏少一個連接), search boxes(這裏少一個連接), filters(這裏少一個連接), date-hierarchies(這裏少一個連接), column-header-ordering(這裏少一個連接) 它們會按照你認爲的那樣一塊兒工做。

自定義admin的外觀

很明顯,在每一個admin頁面的頂部顯示「Django administration」會顯得很愚蠢。它僅起到了佔位符文本的做用。

儘管,使用django的模板系統這個很容易改變。django damin是有django本身提供的,其接口使用了django本身的模板系統。

自定義你的項目的模板

在你的項目目錄(包含manage.py的那個)下建立一個templates目錄。模板能夠保存在django能夠找到的文件系統中的任何位置,(運行服務器的用戶也是運行django的用戶)。無論怎樣。把模板保存在項目中是一個應該遵循的好習慣。

打開你的設置文件(mysite/settings.py),並在 TEMPLATES(少一個連接)中添加一個DIRS(少一個連接)項:

# 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模板時要去檢查文件系統目錄列表,它是一個搜索路徑、

組織模板 就像靜態文件,咱們能夠把全部的模板放在一個大的模板目錄中,它們會工做的很是好。儘管,模板屬於特定的應用,應該放在應用的模板目錄下(例如:polls/templates),而不是項目的模板目錄下(templates)。咱們會在reusable apps tutorial中討論咱們爲何要這樣作。

如今在 templates中建立一個名字是admin的目錄,並從django本身的安裝目錄中(django/contrib/admin/templates)的的django admin模板目錄中把admin/base_site.html複製到這裏來。

django的安裝目錄在哪? 若是你找不到django安裝目錄在你文件系統中的位置,能夠運行下面的命令

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

而後,只要編輯並把 {{ 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模板語言的一部分。當django渲染admin/base_site.html 時,模板語言會評估以生成最終的HTML頁,就像咱們在第三部分中看到的同樣。

注意,任何django admin模板均可以被重寫。要重寫一個模板,和重寫base_site.html的操做同樣 —— 從默認目錄中把模板文件複製到你指定的目錄中,並修改便可。

自定義你的應用的模板

細心的讀者可能會問:但若是DIRS(少一個連接)默認是空目錄,django如何找到默認的admin模板?答案是,因爲APP_DIRS(少一個連接)設置成了True,django會自動在每一個應用包中查找一個templates/子目錄,以做備用(不要忘記django.contrib.admin是一個應用。)

咱們的poll應用不是很複雜,也不須要自定義admin模板。但若是它變得愈來愈複雜,並由於一些功能須要修改django的標準admin模板,明智的方法是修改應用的模板,而不是項目中的模板。使用這種方式,你能夠在任何新項目中使用polls應用,並確保它能夠找到它須要的自定義模板。

更多關於Django如何找到它的模板請查看template loading documentation(少一個連接)

自定義admin默認頁

和上面相似的是,你可能想自定義django admin默認頁的外觀。 默認狀況下,它會按照字母的順序顯示INSTALLED_APPS中全部在admin應用註冊過的應用。你可能會想對佈局作一個大的更改。畢竟,默認頁多是admin中最重要的頁面,它應該易於使用。

要自定義的模板是admin/index.html。(和前面對admin/index.html作的 操做同樣 —— 從默認目錄中複製它到你的自定義模板目錄)。編輯這個文件,你會看到它使用了一個叫app_list的模板變量。這個變量包含全部已安裝的django app。你能夠用你認爲最好的方式將連接硬編碼到特定對象的admin頁面,來替代這個變量。

下一步作什麼

初學者教程到此結束。在此期間,你可能想要去有一些快速連接 where to go from here. 若是你熟悉python打包技術,並對如何將一個app變成一個「可重用的app」,請查看Advanced tutorial: How to write reusable apps(少一個連接)

相關文章
相關標籤/搜索