本節教程承接第六部分(page 11)的教程。咱們繼續開發 web-poll應用,並專一於自定義django的自動生成的admin站點,這點咱們在第二部分(page 7)中探討過。html
經過在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」按鈕添加並保存的行。
如今問題管理頁面看起來看好,咱們在對「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頁面的頂部顯示「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(少一個連接)
和上面相似的是,你可能想自定義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(少一個連接)