已經(jīng)同步到gitbook,想閱讀的請(qǐng)轉(zhuǎn)到gitbook: Django 1.10 中文文檔
Writing your first Django app, part 7?
This tutorial begins where Tutorial 6 left off. We’re continuing the Web-poll application and will focus on customizing Django’s automatically-generated admin site that we first explored in Tutorial 2.
緊接著Tutorial 6。我們繼續(xù)開發(fā)投票應(yīng)用并主要關(guān)注Django自動(dòng)生成的admin站點(diǎn),這部分我們?cè)?a target="_blank" rel="nofollow">教程2中已經(jīng)了解過(guò)。
Customize the admin form?
By registering the Question model with admin.site.register(Question), Django was able to construct a default form representation. Often, you’ll want to customize how the admin form looks and works. You’ll do this by telling Django the options you want when you register the object.
通過(guò)admin.site.register(Question)語(yǔ)句將Question模型注冊(cè)到admin,Django會(huì)自動(dòng)生成該模型的默認(rèn)表單。一般情況下,你需要定制表單的樣式和功能。這樣在你注冊(cè)模型的時(shí)候就需要告訴Django你想要的選項(xiàng)。
Let’s see how this works by reordering the fields on the edit form. Replace the admin.site.register(Question)
line with:
我們通過(guò)演示對(duì)表單字段的重新排序,來(lái)了解其工作原理。用以下代碼替換admin.site.register(Question)語(yǔ)句:
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)
You’ll follow this pattern – create a model admin class, then pass it as the second argument to admin.site.register() – any time you need to change the admin options for a model.
一般遵循以下步驟——?jiǎng)?chuàng)建一個(gè)model admin類,然后作為admin.site.register()的第二個(gè)參數(shù)——你可以隨時(shí)修改模型的admin選項(xiàng)。
This particular change above makes the “Publication date” come before the “Question” field:
這個(gè)操作將使“Publication date” 放在“Question” 字段之前:

This isn’t impressive with only two fields, but for admin forms with dozens of fields, choosing an intuitive order is an important usability detail.
只有兩個(gè)字段的情況下,感覺沒什么作用,但是對(duì)于有幾十個(gè)字段的表單來(lái)說(shuō),采用更直觀的排序方式將是一個(gè)值得引起注意的細(xì)節(jié)問(wèn)題。
And speaking of forms with dozens of fields, you might want to split the form up into fieldsets:
而且對(duì)于有幾十個(gè)字段的表單來(lái)說(shuō),你也許想要通過(guò)fieldsets來(lái)分隔開:
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)
The first element of each tuple in fieldsets is the title of the fieldset. Here’s what our form looks like now:
fieldsets 內(nèi)元組的第一個(gè)字段是fieldsets的標(biāo)題。我們的表單看起來(lái)應(yīng)該像以下這樣了:

Adding related objects?
OK, we have our Question admin page, but a Question
has multiple Choices, and the admin page doesn’t display choices.
好的,我們已經(jīng)有Question的admin頁(yè)面了,但是一個(gè)Question有很多個(gè)Choices,admin頁(yè)面也沒有展示這些choices。
Yet. There are two ways to solve this problem. The first is to register Choice with the admin just as we did with Question. That’s easy:
但是,我們有兩種方法來(lái)解決這個(gè)問(wèn)題。第一種方法是像Question一樣將Choice注冊(cè)到admin站點(diǎn),這非常簡(jiǎn)單:
polls/admin.py
from django.contrib import admin
from .models import Choice, Question
# ...
admin.site.register(Choice)
Now “Choices” is an available option in the Django admin. The “Add choice” form looks like this:
現(xiàn)在“Choices”已經(jīng)展示在Django admin站點(diǎn)了,“增加choice”表單看起來(lái)如下圖:

In that form, the “Question” field is a select box containing every question in the database. Django knows that a ForeignKey should be represented in the admin as a <select> box. In our case, only one question exists at this point.
在這個(gè)表單中,“Question”字段是一個(gè)包含數(shù)據(jù)庫(kù)中所有Question的的單選框。Django知道這是ForeignKey ,應(yīng)該在admin中作為單選框來(lái)展示。在我們的例子中,只有一個(gè)Question存在。
Also note the “Add Another” link next to “Question.” Every object with a ForeignKey relationship to another gets this for free. When you click “Add Another”, you’ll get a popup window with the “Add question” form. If you add a question in that window and click “Save”, Django will save the question to the database and dynamically add it as the selected choice on the “Add choice” form you’re looking at.
同時(shí)注意到Question附近的“增加另一個(gè)”的鏈接按鈕。每個(gè)
ForeignKey 關(guān)系的對(duì)象都會(huì)自動(dòng)有這個(gè)按鈕。當(dāng)你點(diǎn)擊“Add Another”,會(huì)彈出一個(gè)“Add Question”表單。如果你通過(guò)那彈窗點(diǎn)擊save增加一個(gè)Question,Django會(huì)保存這個(gè)Question到數(shù)據(jù)庫(kù)并在 “Add choice”表單中增加一個(gè)可選項(xiàng)。
But, really, this is an inefficient way of adding Choice
objects to the system. It’d be better if you could add a bunch of Choices directly when you create the Question
object. Let’s make that happen.
但是,這真的不是增加Choice高效途徑。當(dāng)你創(chuàng)建一個(gè)Question的時(shí)候,如果你能增加一打choices該多好。讓我們?cè)囋嚳础?/p>
Remove the register() call for the Choice model. Then, edit the Question registration code to read:
去掉register()調(diào)用Choice模型的代碼,然后編輯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)
This tells Django: “Choice objects are edited on the Question admin page. By default, provide enough fields for 3 choices.”
這告訴Django:“Choice對(duì)象可在Question的admin頁(yè)面編輯。默認(rèn)情況下,有3個(gè)choices字段”
Load the “Add question” page to see how that looks:
訪問(wèn)“Add question” 頁(yè),看看它長(zhǎng)啥樣:

It works like this: There are three slots for related Choices – as specified by extra – and each time you come back to the “Change” page for an already-created object, you get another three extra slots.
它的工作原理如下:有3個(gè)表單組件關(guān)聯(lián)Choice對(duì)象,而且當(dāng)你每次回到一個(gè)已存在對(duì)象的change頁(yè)面時(shí),你又會(huì)看到三個(gè)新的表單組件
At the end of the three current slots you will find an “Add another Choice” link. If you click on it, a new slot will be added. If you want to remove the added slot, you can click on the X to the top right of the added slot. Note that you can’t remove the original three slots. This image shows an added slot:
在三個(gè)表單組件的最后,你可以看到“Add another Choice”鏈接,點(diǎn)擊它后,會(huì)創(chuàng)建一個(gè)新的表單選項(xiàng)。。如果你想移除已增加的槽,點(diǎn)擊右上角X即可。注意你不能去掉那三個(gè)原有的槽。下圖展示增加一個(gè)槽:

One small problem, though. It takes a lot of screen space to display all the fields for entering related Choice objects. For that reason, Django offers a tabular way of displaying inline related objects; you just need to change the ChoiceInline declaration to read:
然后,還有個(gè)小問(wèn)題。展示所有關(guān)聯(lián)的Choice對(duì)象會(huì)占據(jù)非常多的屏幕空間。為此,Django提供了一個(gè)扁平化的顯示方式。你只需要將ChoiceInline 類替換即可,如下:
polls/admin.py
class ChoiceInline(admin.TabularInline):
#...

Note that there is an extra “Delete?” column that allows removing rows added using the “Add Another Choice” button and rows that have already been saved.
注意有一個(gè) “Delete?”列,允許你刪除通過(guò)“Add Another Choice” 按鈕增加并保存的行。
Customize the admin change list?
Now that the Question admin page is looking good, let’s make some tweaks to the “change list” page – the one that displays all the questions in the system.
現(xiàn)在Question的admin頁(yè)面已經(jīng)非常漂亮了,我們繼續(xù)對(duì)“change list”做一下微調(diào)——就是那個(gè)展示所有Question列表的頁(yè)面
Here’s what it looks like at this point:
這就是它現(xiàn)在的樣子:

By default, Django displays the str()
of each object. But sometimes it’d be more helpful if we could display individual fields. To do that, use the list_display admin option, which is a tuple of field names to display, as columns, on the change list page for the object:
默認(rèn)情況下,Django調(diào)用str()展示每個(gè)對(duì)象。但是有時(shí)候,如果我們可以展示其他的字段的話,將會(huì)更好。為此,你可以用list_display 選項(xiàng),這是想要展示的字段名的集合,在change list頁(yè)面上將作為列來(lái)展示:
polls/admin.py
class QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ('question_text', 'pub_date')
Just for good measure, let’s also include the was_published_recently()
method from Tutorial 2:
更好的是,我們也可以展示was_published_recently()方法:
polls/admin.py
class QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ('question_text', 'pub_date', 'was_published_recently')
Now the question change list page looks like this:
現(xiàn)在Question的change list頁(yè)面看起來(lái)如下圖:

You can click on the column headers to sort by those values – except in the case of the was_published_recently header, because sorting by the output of an arbitrary method is not supported. Also note that the column header for was_published_recently is, by default, the name of the method (with underscores replaced with spaces), and that each line contains the string representation of the output.
你可以點(diǎn)擊列標(biāo)題來(lái)排序——除了was_published_recently外,因?yàn)閍rbitrary 方法的輸出并不支持排序。同時(shí)注意was_published_recently 列標(biāo)題,默認(rèn)下是函數(shù)名(下劃線替換為了空格),內(nèi)容則是輸出的字符串表示法。
You can improve that by giving that method (in polls/models.py) a few attributes, as follows:
你可以在polls/models.py中增加如下屬性來(lái)修復(fù)這個(gè)問(wè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?'
For more information on these method properties, see list_display.
想了解跟多信息,請(qǐng)看 list_display.
Edit your polls/admin.py file again and add an improvement to the Question change list page: filters using thelist_filter. Add the following line to QuestionAdmin:
再次編輯polls/admin.py,并進(jìn)一步改善Question change list頁(yè)面:用list_filter來(lái)作過(guò)濾器。在QuestionAdmin類里加如下行:
list_filter = ['pub_date']
That adds a “Filter” sidebar that lets people filter the change list by the pub_date field:
這會(huì)增加一個(gè)過(guò)濾器面板,讓用戶可以通過(guò)pub_date 來(lái)過(guò)濾change list頁(yè)面:

The type of filter displayed depends on the type of field you’re filtering on. Because pub_date is a DateTimeField, Django knows to give appropriate filter options: “Any date”, “Today”, “Past 7 days”, “This month”, “This year”.
根據(jù)你選擇的過(guò)濾條件的不同,Django會(huì)在面板中添加不容的過(guò)濾選項(xiàng)。由于pub_date是一個(gè)DateTimeField,因此,Django自動(dòng)添加了這些選項(xiàng):“Any date”, “Today”, “Past 7 days”, “This month”, “This year”。
This is shaping up well. Let’s add some search capability:
為了做的更好。我們?cè)僭黾铀阉骺颍?/p>
search_fields = ['question_text']
That adds a search box at the top of the change list. When somebody enters search terms, Django will search the question_text field. You can use as many fields as you’d like – although because it uses a LIKE query behind the scenes, limiting the number of search fields to a reasonable number will make it easier for your database to do the search.
這會(huì)在頁(yè)面的頂部增加一個(gè)搜索框。當(dāng)輸入搜索關(guān)鍵字后,Django會(huì)在question_text字段內(nèi)進(jìn)行搜索。只要你愿意,你可以使用任意多個(gè)搜索字段,Django在后臺(tái)使用的都是SQL查詢語(yǔ)句的LIKE語(yǔ)法,但是,有限制的搜索字段有助于后臺(tái)的數(shù)據(jù)庫(kù)查詢效率。
Now’s also a good time to note that change lists give you free pagination. The default is to display 100 items per page. Change list pagination, search boxes, filters, date-hierarchies, and column-header-ordering all work together like you think they should.
現(xiàn)在你應(yīng)該注意到 了,change list有分頁(yè)功能,默認(rèn)下顯示100個(gè)每頁(yè)?,F(xiàn)在,Change list pagination, search boxes, filters, date-hierarchies, and column-header-ordering等,都以你想的方式工作了。
Customize the admin look and feel?
定制admin外觀?
Clearly, having “Django administration” at the top of each admin page is ridiculous. It’s just placeholder text.
很明顯,在每一個(gè)admin頁(yè)面頂端都顯示“Django administration”是很可笑的,它僅僅是個(gè)占位文本。
That’s easy to change, though, using Django’s template system. The Django admin is powered by Django itself, and its interfaces use Django’s own template system.
利用Django的模板系統(tǒng),很容易修改它。Django的admin站點(diǎn)是由Django自己驅(qū)動(dòng)的,用的也是Django自己的模板接口。
Customizing your project’s templates?
定制項(xiàng)目模板?
Create a templates directory in your project directory (the one that contains manage.py). Templates can live anywhere on your filesystem that Django can access. (Django runs as whatever user your server runs.) However, keeping your templates within the project is a good convention to follow.
在你的項(xiàng)目目錄(包含manage.py文件的目錄)下創(chuàng)建templates目錄。Templates可以放在任何Django可以訪問(wèn)到的地方。(你的服務(wù)以什么用戶跑,DJango就以什么用戶運(yùn)行)庵后,將你的templates目錄放在project下是非常好的習(xí)慣。
Open your settings file (mysite/settings.py
, remember) and add a DIRS option in the TEMPLATES setting:
打開settings配置文件(mysite/settings.py, 記住 ),TEMPLATES 設(shè)置中增加 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 is a list of filesystem directories to check when loading Django templates; it’s a search path.
DIRS是一個(gè)文件系統(tǒng)目錄的列表,當(dāng)加載Django模板時(shí),會(huì)在DIRS中進(jìn)行查找。它是搜索路徑。
Organizing templates
Just like the static files, we could have all our templates together, in one big templates directory, and it would work perfectly well. However, templates that belong to a particular application should be placed in that application’s template directory (e.g. polls/templates) rather than the project’s (templates). We’ll discuss in more detail in the reusable apps tutorial why we do this.
組織templates
就像靜態(tài)文件一樣,我們可以把所有的模板都放在一起,形成一個(gè)大大的模板文件夾,并且工作正常。但是我們不建議這樣!我們建議每一個(gè)模板都應(yīng)該存放在它所屬應(yīng)用的模板目錄內(nèi)(例如polls/templates)而不是整個(gè)項(xiàng)目的模板目錄(templates),因?yàn)檫@樣每個(gè)應(yīng)用才可以被方便和正確的重用。請(qǐng)參考2.10節(jié)《如何重用apps》。
Now create a directory called admin inside templates, and copy the template admin/base_site.html from within the default Django admin template directory in the source code of Django itself (django/contrib/admin/templates) into that directory.
接下來(lái),在剛才創(chuàng)建的templates中創(chuàng)建一個(gè)admin目錄,將admin/base_site.html模板文件拷貝到該目錄內(nèi)。這個(gè)html文件來(lái)自Django源碼,它位于django/contrib/admin/templates目錄內(nèi)。
Where are the Django source files?
If you have difficulty finding where the Django source files are located on your system, run the following command:
如果你不知道Django的源代碼文件在哪,運(yùn)行以下命令:
$ python -c "import django; print(django.__path__)"```
Then, just edit the file and replace{% raw %} {{ site_header|default:_('Django administration') }}{% endraw %} (including the curly braces) with your own site’s name as you see fit. You should end up with a section of code like:
編輯該文件,用你喜歡的站點(diǎn)名字替換掉{% raw %} {{ site_header|default:_('Django administration') }}{% endraw %}(包括兩個(gè)大括號(hào)一起),看起來(lái)像下面這樣:
{% block branding %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% endblock %}
We use this approach to teach you how to override templates. In an actual project, you would probably use the [django.contrib.admin.AdminSite.site_header](https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.AdminSite.site_header) attribute to more easily make this particular customization.
在這里,我們使用這個(gè)方法教會(huì)你如何重寫模板。但是在實(shí)際的項(xiàng)目中,你可以使用 [django.contrib.admin.AdminSite.site_header](https://docs.djangoproject.com/en/1.10/ref/contrib/admin/#django.contrib.admin.AdminSite.site_header),方便的對(duì)這個(gè)頁(yè)面title進(jìn)行自定義。
This template file contains lots of text like {% block branding %} and {{ title }}. The {%
and {{ tags are part of Django’s template language. When Django renders admin/base_site.html, this template language will be evaluated to produce the final HTML page, just like we saw in [Tutorial 3](https://docs.djangoproject.com/en/1.10/intro/tutorial03/).
這個(gè)模板文件包含了大量的如{% raw %}{% block branding %} and {{ title }}{% endraw %},{% raw %} {% and {{ {% endraw %}是Django的模板語(yǔ)言。當(dāng)Django渲染 admin/base_site.html文件時(shí),這些模板語(yǔ)言會(huì)生成最終的HTML頁(yè)面,就像[Tutorial 3](https://docs.djangoproject.com/en/1.10/intro/tutorial03/)所說(shuō)
Note that any of Django’s default admin templates can be overridden. To override a template, just do the same thing you did with base_site.html – copy it from the default directory into your custom directory, and make changes.
請(qǐng)注意,所有Django默認(rèn)的admin模板都可以被重寫。類似剛才重寫base_site.html模板的方法一樣,從源代碼目錄將html文件拷貝至你自定義的目錄內(nèi),然后修改文件。
#### **Customizing your *application’s* templates[?](https://docs.djangoproject.com/en/1.10/intro/tutorial07/#customizing-your-application-s-templates)**
#### **定制 *application’s* 模板[?](https://docs.djangoproject.com/en/1.10/intro/tutorial07/#customizing-your-application-s-templates)**
Astute readers will ask: But if [DIRS](https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-TEMPLATES-DIRS) was empty by default, how was Django finding the default admin templates? The answer is that, since [APP_DIRS](https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-TEMPLATES-APP_DIRS) is set to True, Django automatically looks for a templates/ subdirectory within each application package, for use as a fallback (don’t forget that django.contrib.admin is an application).
聰明的讀者可能會(huì)問(wèn):但是DIRS默認(rèn)是空的,Django是如何找到默認(rèn)的admin模板呢?回答是,由于APP_DIRS被設(shè)置為True,Django將自動(dòng)查找每一個(gè)應(yīng)用包內(nèi)的templates/子目錄(不要忘了django.contrib.admin也是一個(gè)應(yīng)用)。
Our poll application is not very complex and doesn’t need custom admin templates. But if it grew more sophisticated and required modification of Django’s standard admin templates for some of its functionality, it would be more sensible to modify the *application’s* templates, rather than those in the *project*. That way, you could include the polls application in any new project and be assured that it would find the custom templates it needed.
我們的投票應(yīng)用不太復(fù)雜,因此不需要自定義admin模板。但是如果它變得越來(lái)越復(fù)雜,因?yàn)槟承┕δ芏枰薷腄jango的標(biāo)準(zhǔn)admin模板,那么修改app的模板就比修改項(xiàng)目的模板更加明智。這樣的話,你可以將投票應(yīng)用加入到任何新的項(xiàng)目中,并且保證能夠找到它所需要的自定義模板。
See the [template loading documentation](https://docs.djangoproject.com/en/1.10/topics/templates/#template-loading) for more information about how Django finds its templates.
查看[template loading documentation](https://docs.djangoproject.com/en/1.10/topics/templates/#template-loading)獲取更多關(guān)于Django如何查找模板的信息。
#### **Customize the admin index page[?](https://docs.djangoproject.com/en/1.10/intro/tutorial07/#customize-the-admin-index-page)**
#### **定制admin 首頁(yè)[?](https://docs.djangoproject.com/en/1.10/intro/tutorial07/#customize-the-admin-index-page)**
On a similar note, you might want to customize the look and feel of the Django admin index page.
很多人都會(huì)想定制化Django admin的首頁(yè)的外觀和感覺。
By default, it displays all the apps in [INSTALLED_APPS](https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-INSTALLED_APPS) that have been registered with the admin application, in alphabetical order. You may want to make significant changes to the layout. After all, the index is probably the most important page of the admin, and it should be easy to use.
默認(rèn)情況下,首頁(yè)展示所有[INSTALLED_APPS](https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-INSTALLED_APPS) 中被注冊(cè)到admin的應(yīng)用,你或許想改變一下布局。畢竟,首頁(yè)是admin站點(diǎn)最重要的頁(yè)面,它應(yīng)該要簡(jiǎn)單易用。
The template to customize is admin/index.html. (Do the same as with admin/base_site.html in the previous section – copy it from the default directory to your custom template directory). Edit the file, and you’ll see it uses a template variable called app_list. That variable contains every installed Django app. Instead of using that, you can hard-code links to object-specific admin pages in whatever way you think is best.
要定制的模板是admin/index.html,(像上節(jié)中更改admin/base_site.html模板一樣,從它默認(rèn)的目錄拷貝到你的定制化模板目錄)。編輯文件,你會(huì)看到模板有一個(gè)app_list的變量。你可以硬編碼鏈接到指定對(duì)象的admin頁(yè)面,使用任何你認(rèn)為好的方法,用于替代這個(gè)app_list。
#### **What’s next?[?](https://docs.djangoproject.com/en/1.10/intro/tutorial07/#what-s-next)**
#### **接下來(lái)學(xué)習(xí)什么?[?](https://docs.djangoproject.com/en/1.10/intro/tutorial07/#what-s-next)**
The beginner tutorial ends here. In the meantime, you might want to check out some pointers on [where to go from here](https://docs.djangoproject.com/en/1.10/intro/whatsnext/).
入門教程到這里就結(jié)束了。此時(shí),你應(yīng)該轉(zhuǎn)到 [where to go from here](https://docs.djangoproject.com/en/1.10/intro/whatsnext/)看看接下該學(xué)習(xí)什么
If you are familiar with Python packaging and interested in learning how to turn polls into a “reusable app”, check out [Advanced tutorial: How to write reusable apps](https://docs.djangoproject.com/en/1.10/intro/reusable-apps/).
或者你對(duì)Python包機(jī)制很熟悉,對(duì)如何將投票應(yīng)用轉(zhuǎn)換成一個(gè)可重用的app感興趣,請(qǐng)看[Advanced tutorial: How to write reusable apps](https://docs.djangoproject.com/en/1.10/intro/reusable-apps/).