编写第一个Django应用:第二部分
第二部分将会继续完成第一部分剩余的内容。我们会继续我们的Poll应用以及聚焦到Django自动生成的admin页面。
还记得教程1里你这样启动开发用服务器吧:
现在,打开浏览器访问你本地域名上的"/admin/" —— 例如,
http://127.0.0.1:8000/admin/。你应该可以看到admin的登录界面:
你应该会看到一些其他的可编辑内容,包括群组,用户和网站。这些核心的功能默认包含在Django里。
我们只需做一件事:告诉admin, Poll对象需要一个admin界面。在你的 polls文件夹里创建一个名字叫 admin.py的文件,然后编辑成以下样子:
要看到这些修改生效,你需要重启开发用服务器。通常,当你修改文件后服务器会自动重载代码,但是创建一个新文件并不会触发自动重载。
点击"Polls"。现在你在polls的"change list"页面上。这个页面显示了数据库里所有的poll,你可以选择其中一个进行编辑。我们可以看到我们教程1里创建的"What's up?" poll:
点击"What's up?"进行编辑:
这里需要注意几点:
让我们通过重新排列编辑表单的字段顺序来看看这是怎么做到的。把 admin.site.register(Poll)这一行换成:
你需要使用这个模式 —— 在你想修改一个对象的admin选项时,先创建一个模型的admin对象,然后作为第二个参数传进
admin.site.register()里。
上面的修改使"Publication date"位于"Question"字段的前面:
就两个字段的话没什么大不了,但是如果是对于有几十个字段的表单来说,选择更为直观的顺序对可用性来说是一个重要的细节。
说到有几十个字段的表格,你可能会想把表格的字段分组:
在fieldsets里,元组(tuple)的第一个元素是fieldset的标题。现在我们的表格看起来会像这样:
你可以给fieldset分配任意的HTML类名。Django提供了一个 "collapse"类,使特定的一个fieldset在初始时闭合显示。当你有一个很长的表单包含若干不常用的字段时,这个类就会很有用。
有两个方法解决这个问题。第一个方法是在admin那注册一个 Choice,就跟我们刚才注册 Poll一样。这个很简单:
现在"Choices"选项已经出现在Django的admin里了。"Add choice"表单看起来就像这样:
在这个表单里,"Poll"字段是一个下拉框,它包含了数据库里所有的poll。Django知道应该把外键( ForeignKey)呈现为一个下拉框。所以在我们这里,下拉框只有一个poll。
注意到"Poll"旁边有个"Add Another"链接。每一个用 外键关联的对象都有这么一个链接。当年点击"Add Another"的时候,将会弹出一个包含"Add poll"表单的窗口。如果你在这个窗口添加了一个poll并点击"Save",Django就会把这个poll保存到数据库里并动态的把它加到下拉框里。
但是事实上,这是一个很低效的添加Choice对象的方法。如果能直接在创建Poll对象时添加一些Choice,这才是更好的方法。让我们来实现它吧。
把为Choice模型调用的 register()删掉,然后编辑注册Poll的代码:
这段代码告诉Django:“Choice对象放到Poll的管理页面里进行编辑。页面默认提供足够添加3个choice的字段。”
打开"Add poll"页面看看效果,你可能需要重启开发服务器:
它是这样工作的:在页面上有三行空间用来关联Choice——由 extra指定。每次你回到一个已经创建好的对象的"Change"页面时,除了已经存在的关联的choice外,你还可以看到另外三个额外的空间用来创建新的Choice。
还有一个小问题,要显示这三个用来关联Choice对象的所有字段,需要霸占很大的屏幕空间,因此,Django提供了一个表格方式来显示这些关联的对象。你只需要把ChoiceInline改成下面这样:
使用TabularInline(而不是StackedInline)后,关联的对象就会以一个更紧凑的表格式显示出来:
现在它是这个样子的:
Django默认会调用每个对象的 str()作显示。但是有时我们会想显示某些个别更有用的字段。这个时候,我们需要用到 list_display这个选项,它是一个要显出的字段名字的元组(tuple),这些名字将会作为列名显示在对象的修改列表页面上。
Just for good measure, let's also include the was_published_today custom method from Tutorial 1:
现在poll的修改列表页面看起来会是这样:
你可以点击的列头进行排序——除了 was_published_today那一列,因为现在还不支持对方法输出的值进行排序。同时还需要注意的是, was_published_today那一列的列头的名字默认是方法的名字(下划线会用空格代替)。但是你可以通过给方法(在 models.py里)一个 short_description属性来修改它。
再次编辑admin.py对Poll的修改列表页面加个功能:过滤(Filters)。在 PollAdmin里增加如下代码:
它会增加一个"Filter"侧边栏让用户可以通过pub_date字段对修改列表进行过滤:
显示的过滤类型取决于要进行过滤的字段的类型。因为pub_date是一个DateTimeField,Django知道默认需要给DateTimeFields这些过滤选项:"Any date", "Today", "Past 7 days", "This month"和"This year"。
目前情况进展的还不错。让我们添加一些搜索的功能:
它会在修改列表顶部增加一个搜索框。当输入一些搜索词,Django会去搜索
question字段。只要你喜欢,你可以使用任意多的字段——但是因为它背后是使用
LIKE进行查询,所以尽量合理一点,以免你的数据库不高兴。
最后,因为Poll对象有日期,所以如果能根据日期进行筛选就会显得比较方便。增加以下代码:
它会在修改列表页面的顶部根据日期增加一个层级性导航。在最顶层他会显示所有有效的年份,然后逐层深入到月份和天。
修改列表页面自带分页功能,默认每页显示50条记录。分页,搜索框,过滤,日期层级和排序,它们就像你所期待的那样一起运作着。
但这个使用Django的模板系统很容易就能修改。Django的管理系统是使用Django自身实现的,它的界面使用的是Django本事的模板系统。
打开配置文件( mysite/settings.py)并找到 TEMPLATE_DIRS这个设置。 TEMPLATE_DIRS是一个文件系统路径的元组(tuple),在加载Django模板时会对它进行检查。它是一个搜索路径。
TEMPLATE_DIRS默认是空的。所以,我们增加一行代码进去,告诉Django我们的模板放在哪:
现在把模板文件
admin/base_site.html从Django源码(
django/contrib/admin/templates)的admin模板目录里复制到你在
TEMPLATE_DIRS里设置的目录里的一个子目录admin。例如,如果你的
TEMPLATE_DIRS包含'
/home/my_username/mytemplates',就像上面设置一样,那么就复制
django/contrib/admin/templates/admin/base_site.html到
/home/my_username/mytemplates/admin/base_site.html。别忘了admin这个子目录。
然后,编辑那个模板文件,并把Django那段通用文本替换成你想要显示的网站名。
这个模板文件包含了很多像 {% block branding %}和 {{ title }}这样的文本。 {%和 {{标签是Django模板语言中的一部分。当Django渲染 admin/base_site.html时,这个模板语言将会被评估产生出最后的HTML页面。如果你现在对模板还没啥概念的话,别担心,我们将在教程3里深入Django的模板语言。
所有的Django的默认admin模板都可以被重写,要重写一个模板,你只需要重复刚才操作 base_site.html的步骤——从默认目录复制到你自定义的目录里并修改。
精明的读者也许会问:如果 TEMPLATE_DIRS默认为空,Django是怎样找到默认的admin模板的?答案是,Django默认会自动在每个app包里寻找 templates/这个子目录。想知道全部信息,可以看 template loader documentation。
在默认情况下,admin会显示注册过的所有在 INSTALLED_APPS设置的app,并按字母进行排序。你也许想要把界面弄得更有意义,毕竟,首页可能是admin里最重要的页面了,它应该做到易于使用。
需要自定义的模板是 admin/index.html。(像前一部分对 admin/base_site.html做的那样——把它从默认目录复制到你的自定义模板目录里。)编辑这个文件,你会看到它使用了一个模板变量叫 app_list。这个变量包含了所有已经安装的Django app。如果你不想使用它,你可以在你想要放置的位置硬编码链接到对象相应的admin页面。再次的,如果你搞不懂模板语言,我们将会在教程3进行详情讲解。
如果你对管理网站感觉良好,那么可以开始关于poll公共视图的教程的第三部分了。
教程第二部分原文: https://docs.djangoproject.com/en/dev/intro/tutorial02/
本文也发表在这里: http://www.icyfire.me/2011/10/writing-your-first-django-app-part-2/
原理
为你的员工和客户产生admin网页来管理内容是件乏味和无需创造力的事情。因此,Django为模型全自动的创建了admin界面。
Django是在“内容发布者”页面和“公共”页面分界很清晰的这样一个环境下编写的,网站的管理者使用这个系统添加新闻,事件,比赛比分等等的内容,然后这些内容会显示在公共网页上。Django提供了一个统一的界面让管理员编辑内容。
admin功能对网页访问者来说不是必要的,它是给管理员用的。
激活admin网页(Activate the admin site)
Django的admin页面默认是没有激活的,要想激活它,你需要做三件事情:- 添加"django.contrib.admin"到你的INSTALLED_APPS设置里。
- 运行python manage.py syncdb。既然你已经添加了一个新的应用到INSTALLED_APPS里,数据库里的表自然也需要更新。
- 编辑文件mysite/urls.py反注释跟admin有关的行 —— 一共有三行需要注释。这个文件是一个url配置文件,我们将会在下一个教程深入URL的配置。现在,你所需要知道的就是它会把URL映射到应用上。 做完这些后,文件urls.py应该类似下面这样:
from
django.conf.urls
import
patterns, include, url
# 反注释下两行开启admin功能:
from
django.contrib
import
admin
admin.autodiscover()
urlpatterns
=
patterns('',
# 例子:
# url(r'^$', '{{ project_name }}.views.home', name='home'),
# url(r'^{{ project_name }}/', include('{{ project_name }}.foo.urls')),
# 反注释admin/doc这一行开启管理文档url:
# url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
# 反注释下一行开启管理页面url:
url(r
'^admin/'
, include(admin.site.urls)),
)
启动开发服务器(Start the development server)
我们启动开发用服务器,然后打开admin页面。还记得教程1里你这样启动开发用服务器吧:
python manage.py runserver
|
![Django admin](https://i-blog.csdnimg.cn/blog_migrate/9ff361ecf5638751926930b79c15745b.png)
进入admin页面(Enter the admin site)
现在我们试试登录。(你在教程1里已经创建过一个超级用户帐号,还记得吗?如果你没有或者忘记了密码,你可以 再创建一个。)登录后你会看到Django的admin首页:![django_admin_02](https://i-blog.csdnimg.cn/blog_migrate/5dfe6665bb26f3e27104ecf66b3664c6.png)
你应该会看到一些其他的可编辑内容,包括群组,用户和网站。这些核心的功能默认包含在Django里。
让poll应用可修改(Make the poll app modifiable in the admin)
但是我们的poll应用在哪呢?它没有在admin的首页显示。我们只需做一件事:告诉admin, Poll对象需要一个admin界面。在你的 polls文件夹里创建一个名字叫 admin.py的文件,然后编辑成以下样子:
from
polls.models
import
Poll
from
django.contrib
import
admin
admin.site.register(Poll)
|
admin功能探索(Explore the free admin functionality)
现在我们已经注册好 Poll了,Django知道要把它显示在admin首页上。![django_admin_03](https://i-blog.csdnimg.cn/blog_migrate/9bda9f58765072cb902eece8699a9bd9.png)
点击"Polls"。现在你在polls的"change list"页面上。这个页面显示了数据库里所有的poll,你可以选择其中一个进行编辑。我们可以看到我们教程1里创建的"What's up?" poll:
![django_admin_04](https://i-blog.csdnimg.cn/blog_migrate/80f2f22c53070a89c1a609a83838a113.png)
点击"What's up?"进行编辑:
![django_admin_05](https://i-blog.csdnimg.cn/blog_migrate/d46738484d609809a1a56de2cf1b0f4a.jpeg)
这里需要注意几点:
- 表格是根据Poll模型自动生成的。
- 不同模型字段类型(DateTimeField,CharField)对应到相应的HTML的input组件。 Django的admin知道每种类型的字段该怎么显示。
- 每个DateTimeField都有一些Javascript快捷操作功能。日期有"Today"快捷操作和弹出的日历,时间有"Now"快捷操作和列出常用时间输入的弹出窗口。
- 保存 -- 保存修改并返回到这类型对象的修改列表页面。
- 保存并继续编辑 -- 保存修改并重新加载这个对象的admin页面。
- 保存并添加新记录 -- 保存修改并加载一个这个类型对象的新的空白表格。
- 删除 -- 显示一个确认删除的页面。
![django_admin_06](https://i-blog.csdnimg.cn/blog_migrate/f41846d0c4dbafd67d1b74ace88e1b66.jpeg)
自定义admin表单(Customize the admin form)
花几分钟时间去感叹下你少写了多少代码!通过用 admin.site.register(Poll)注册Poll模型,Django可以构建一个默认的表单显示出来。通常你会想自定义admin表单的样子和功能,这时你可以在注册对象的时候告诉Django你想要的选项。让我们通过重新排列编辑表单的字段顺序来看看这是怎么做到的。把 admin.site.register(Poll)这一行换成:
class
PollAdmin(admin.ModelAdmin):
fields
=
[
'pub_date'
,
'question'
]
admin.site.register(Poll, PollAdmin)
|
上面的修改使"Publication date"位于"Question"字段的前面:
![django_admin_07](https://i-blog.csdnimg.cn/blog_migrate/bf67f801f6cd0e4264c268fe4d00d95e.png)
就两个字段的话没什么大不了,但是如果是对于有几十个字段的表单来说,选择更为直观的顺序对可用性来说是一个重要的细节。
说到有几十个字段的表格,你可能会想把表格的字段分组:
class
PollAdmin(admin.ModelAdmin):
fieldsets
=
[
(
None
, {
'fields'
: [
'question'
]}),
(
'Date information'
, {
'fields'
: [
'pub_date'
]}),
]
admin.site.register(Poll, PollAdmin)
|
![django_admin_08](https://i-blog.csdnimg.cn/blog_migrate/eaf508cc6d686c1b565869a1f1470549.png)
你可以给fieldset分配任意的HTML类名。Django提供了一个 "collapse"类,使特定的一个fieldset在初始时闭合显示。当你有一个很长的表单包含若干不常用的字段时,这个类就会很有用。
class
PollAdmin(admin.ModelAdmin):
fieldsets
=
[
(
None
, {
'fields'
: [
'question'
]}),
(
'Date information'
, {
'fields'
: [
'pub_date'
],
'classes'
: [
'collapse'
]}),
]
|
![django_admin_09](https://i-blog.csdnimg.cn/blog_migrate/1e72e0b0a97c4b5aae6a7610905420c3.png)
添加关联对象(Adding related objects)
好了,我们有了Poll的管理页面了。但是一个 Poll有多个 Choices,而管理页面并没有显示choice。有两个方法解决这个问题。第一个方法是在admin那注册一个 Choice,就跟我们刚才注册 Poll一样。这个很简单:
from
polls.models
import
Choice
admin.site.register(Choice)
|
![django_admin](https://i-blog.csdnimg.cn/blog_migrate/d47b6fa7bbd28ed5819be881a6a12e35.png)
在这个表单里,"Poll"字段是一个下拉框,它包含了数据库里所有的poll。Django知道应该把外键( ForeignKey)呈现为一个下拉框。所以在我们这里,下拉框只有一个poll。
注意到"Poll"旁边有个"Add Another"链接。每一个用 外键关联的对象都有这么一个链接。当年点击"Add Another"的时候,将会弹出一个包含"Add poll"表单的窗口。如果你在这个窗口添加了一个poll并点击"Save",Django就会把这个poll保存到数据库里并动态的把它加到下拉框里。
但是事实上,这是一个很低效的添加Choice对象的方法。如果能直接在创建Poll对象时添加一些Choice,这才是更好的方法。让我们来实现它吧。
把为Choice模型调用的 register()删掉,然后编辑注册Poll的代码:
class
ChoiceInline(admin.StackedInline):
model
=
Choice
extra
=
3
class
PollAdmin(admin.ModelAdmin):
fieldsets
=
[
(
None
, {
'fields'
: [
'question'
]}),
(
'Date information'
, {
'fields'
: [
'pub_date'
],
'classes'
: [
'collapse'
]}),
]
inlines
=
[ChoiceInline]
admin.site.register(Poll, PollAdmin)
|
打开"Add poll"页面看看效果,你可能需要重启开发服务器:
![django_admin_11](https://i-blog.csdnimg.cn/blog_migrate/79b7f1ad7bbcfc61752d17679eda87af.jpeg)
它是这样工作的:在页面上有三行空间用来关联Choice——由 extra指定。每次你回到一个已经创建好的对象的"Change"页面时,除了已经存在的关联的choice外,你还可以看到另外三个额外的空间用来创建新的Choice。
还有一个小问题,要显示这三个用来关联Choice对象的所有字段,需要霸占很大的屏幕空间,因此,Django提供了一个表格方式来显示这些关联的对象。你只需要把ChoiceInline改成下面这样:
class
ChoiceInline(admin.TabularInline):
#...
|
![django_admin_12](https://i-blog.csdnimg.cn/blog_migrate/0b467683f9d82906ea4f5fecae3ac513.jpeg)
自定义修改列表页面(Customize the admin change list)
现在Poll管理页面看起来还不错,让我们对"change list"页面——显示所有poll的那个页面做点调整。现在它是这个样子的:
![django_admin_13](https://i-blog.csdnimg.cn/blog_migrate/470842e5861c35b232c848f4fa6bd08d.jpeg)
Django默认会调用每个对象的 str()作显示。但是有时我们会想显示某些个别更有用的字段。这个时候,我们需要用到 list_display这个选项,它是一个要显出的字段名字的元组(tuple),这些名字将会作为列名显示在对象的修改列表页面上。
class
PollAdmin(admin.ModelAdmin):
# ...
list_display
=
(
'question'
,
'pub_date'
)
|
class
PollAdmin(admin.ModelAdmin):
# ...
list_display
=
(
'question'
,
'pub_date'
,
'was_published_today'
)
|
![django_admin_14](https://i-blog.csdnimg.cn/blog_migrate/ea7ab242308560881cffe8088c7982e7.png)
你可以点击的列头进行排序——除了 was_published_today那一列,因为现在还不支持对方法输出的值进行排序。同时还需要注意的是, was_published_today那一列的列头的名字默认是方法的名字(下划线会用空格代替)。但是你可以通过给方法(在 models.py里)一个 short_description属性来修改它。
def
was_published_today(
self
):
return
self
.pub_date.date()
=
=
datetime.date.today()
was_published_today.short_description
=
'Published today?'
|
再次编辑admin.py对Poll的修改列表页面加个功能:过滤(Filters)。在 PollAdmin里增加如下代码:
list_filter
=
[
'pub_date'
]
|
![django_admin_15](https://i-blog.csdnimg.cn/blog_migrate/0d35a227cb3f59d8f4c07468ebf34f0b.png)
显示的过滤类型取决于要进行过滤的字段的类型。因为pub_date是一个DateTimeField,Django知道默认需要给DateTimeFields这些过滤选项:"Any date", "Today", "Past 7 days", "This month"和"This year"。
目前情况进展的还不错。让我们添加一些搜索的功能:
search_fields
=
[
'question'
]
|
最后,因为Poll对象有日期,所以如果能根据日期进行筛选就会显得比较方便。增加以下代码:
date_hierarchy
=
'pub_date'
|
修改列表页面自带分页功能,默认每页显示50条记录。分页,搜索框,过滤,日期层级和排序,它们就像你所期待的那样一起运作着。
自定义管理界面(Customize the admin look and feel)
很明显,在每个管理页面的顶部显示Django administratio是很荒谬的,它只是个占位用文本。但这个使用Django的模板系统很容易就能修改。Django的管理系统是使用Django自身实现的,它的界面使用的是Django本事的模板系统。
打开配置文件( mysite/settings.py)并找到 TEMPLATE_DIRS这个设置。 TEMPLATE_DIRS是一个文件系统路径的元组(tuple),在加载Django模板时会对它进行检查。它是一个搜索路径。
TEMPLATE_DIRS默认是空的。所以,我们增加一行代码进去,告诉Django我们的模板放在哪:
TEMPLATE_DIRS
=
(
'/home/my_username/mytemplates'
,
# 这里改为你自己的路径。
)
|
然后,编辑那个模板文件,并把Django那段通用文本替换成你想要显示的网站名。
这个模板文件包含了很多像 {% block branding %}和 {{ title }}这样的文本。 {%和 {{标签是Django模板语言中的一部分。当Django渲染 admin/base_site.html时,这个模板语言将会被评估产生出最后的HTML页面。如果你现在对模板还没啥概念的话,别担心,我们将在教程3里深入Django的模板语言。
所有的Django的默认admin模板都可以被重写,要重写一个模板,你只需要重复刚才操作 base_site.html的步骤——从默认目录复制到你自定义的目录里并修改。
精明的读者也许会问:如果 TEMPLATE_DIRS默认为空,Django是怎样找到默认的admin模板的?答案是,Django默认会自动在每个app包里寻找 templates/这个子目录。想知道全部信息,可以看 template loader documentation。
自定义管理首页(Customize the admin index page)
基于近似的理由,你可能像自定义Django管理系统的首页。在默认情况下,admin会显示注册过的所有在 INSTALLED_APPS设置的app,并按字母进行排序。你也许想要把界面弄得更有意义,毕竟,首页可能是admin里最重要的页面了,它应该做到易于使用。
需要自定义的模板是 admin/index.html。(像前一部分对 admin/base_site.html做的那样——把它从默认目录复制到你的自定义模板目录里。)编辑这个文件,你会看到它使用了一个模板变量叫 app_list。这个变量包含了所有已经安装的Django app。如果你不想使用它,你可以在你想要放置的位置硬编码链接到对象相应的admin页面。再次的,如果你搞不懂模板语言,我们将会在教程3进行详情讲解。
如果你对管理网站感觉良好,那么可以开始关于poll公共视图的教程的第三部分了。
教程第二部分原文: https://docs.djangoproject.com/en/dev/intro/tutorial02/
本文也发表在这里: http://www.icyfire.me/2011/10/writing-your-first-django-app-part-2/