开发第一个Django应用,Part7

  本教程上接Part6。将继续完成这个投票应用,本节将着重讲解如果用Django自动生成后台管理网站。

自定义管理表单

  通过admin.site.register(Question)注册了Question后,Django可以自动构建一个默认的表单。如果您需要自定义管理表单的外观和功能。你可以在注册时通过配置来实现。

  现在先来试试重新排序表单上的字段。只需要将admin.site.register(Question)所在行替换为:

  1. # polls/admin.py
  2. from django.contrib import admin
  3. from .models import Question
  4. class QuestionAdmin(admin.ModelAdmin):
  5. fields = ['pub_date', 'question_text']
  6. admin.site.register(Question, QuestionAdmin)

  你可以参照上面的形式,创建一个模型类,将之作为第二个参数传入admin.site.register()。而且这种操作在任何时候都可以进行。

  经过上面修改”Publication date”字段会在”Question”字段前面:

  目前的表单只有两个字段可能看不出什么,但是对于一个字段很多的表单,设计一个直观合理的排序方式非常重要。并且在字段数据很多时,还可以将表单分割成多个字段的集合:

  1. # polls/admin.py
  2. from django.contrib import admin
  3. from .models import Question
  4. class QuestionAdmin(admin.ModelAdmin):
  5. fieldsets = [
  6. (None, {'fields': ['question_text']}),
  7. ('Date information', {'fields': ['pub_date']}),
  8. ]
  9. admin.site.register(Question, QuestionAdmin)

  字段集合中每一个元组的第一个元素是该字段集合的标题。它让页面看起来像下面的样子:

添加关联对象

  现在Question的管理页面有了,但是一个Question应该有多个Choices。而此时管理页面并没有显示。现在有两个方法可以解决这个问题。一是就像刚刚Question一样也将Choice注册到admin界面。代码像这样:

  1. # polls/admin.py
  2. from django.contrib import admin
  3. from .models import Choice, Question
  4. # ...
  5. admin.site.register(Choice)

  现在Choice也可以在admin页面看见了,其中”Add choice”表单应该类似这样:

  在这个表单中,Question字段是一个select选择框,包含了当前数据库中所有的Question实例。Django在admin站点中,自动地将所有的外键关系展示为一个select框。在我们的例子中,目前只有一个question对象存在。

  请注意图中的绿色加号,它连接到Question模型。每一个包含外键关系的对象都会有这个绿色加号。点击它,会弹出一个新增Question的表单,类似Question自己的添加表单。填入相关信息点击保存后,Django自动将该Question保存在数据库,并作为当前Choice的关联外键对象。通俗讲就是,新建一个Question并作为当前Choice的外键。

  但是,实话说,这种创建方式的效率不怎么样。如果在创建Question对象的时候就可以直接添加一些Choice,那样操作将会变得简单些。

  删除Choice模型对register()方法的调用。然后,编辑Question的注册代码如下:

  1. # polls/admin.py
  2. from django.contrib import admin
  3. from .models import Choice, Question
  4. class ChoiceInline(admin.StackedInline):
  5. model = Choice
  6. extra = 3
  7. class QuestionAdmin(admin.ModelAdmin):
  8. fieldsets = [
  9. (None, {'fields': ['question_text']}),
  10. ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
  11. ]
  12. inlines = [ChoiceInline]
  13. admin.site.register(Question, QuestionAdmin)

  上面的代码告诉Django:Choice对象将在Question管理页面进行编辑,默认情况,请提供3个Choice对象的编辑区域。

  现在”增加question”页面变成了这样:

  它的工作机制是:这里有3个插槽用于关联Choices,而且每当你重新返回一个已经存在的对象的“Change”页面,你又将获得3个新的额外的插槽可用。

  在3个插槽的最后,还有一个“Add another Choice”链接。点击它,又可以获得一个新的插槽。如果你想删除新增的插槽,点击它右上方的X图标即可。但是,默认的三个插槽不可删除。下面是新增插槽的样子:

  但是现在还有个小问题。上面页面中插槽纵队排列的方式需要占据大块的页面空间,看起来很不方便。为此,Django提供了一种扁平化的显示方式,你仅仅只需要将ChoiceInline继承的类改为admin.TabularInline:

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

  使用TabularInline代替`StackedInline``,相关的对象将以一种更紧凑的表格形式显示出来:

  注意,这样多了一个”删除”选项,它允许你删除已经存在的Choice.

自定义修改列表

  现在Question的管理页面看起来已经差不多了,下面来看看修改列表页面,也就是显示了所有question的页面,即下图这个页面:

  Django默认只显示str()方法指定的内容。如果我们想要同时显示一些别的内容,可以使用list_display属性,它是一个由多个字段组成的元组,其中的每一个字段都会按顺序显示在页面上,代码如下:

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

  同时,还可以把Part2中的was_published_recently()方法也加入进来:

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

  现在question的修改列表页面看起来像这样:

  你可以点击其中一列的表头来让列表按照这列的值来进行排序,但是was_published_recently这列的表头不行,因为Django不支持按照随便一个方法的输出进行排序。另请注意,默认情况下,was_published_recently的列标题是方法的名称(下划线替换为空格),内容则是输出的字符串表示形式。

  可以通过给方法提供一些属性来改进输出的样式,就如下面所示:

  1. # polls/models.py
  2. class Question(models.Model):
  3. # ...
  4. def was_published_recently(self):
  5. now = timezone.now()
  6. return now - datetime.timedelta(days=1) <= self.pub_date <= now
  7. was_published_recently.admin_order_field = 'pub_date'
  8. was_published_recently.boolean = True
  9. was_published_recently.short_description = 'Published recently?'

  关于这些方法属性的更多信息,请参见list_display
  
  我们还可以对显示结果进行过滤,通过使用list_filter属性。在QuestionAdmin中添加下面的代码:

  1. list_filter = ['pub_date']

  它添加了一个“过滤器”侧边栏,这样就可以通过pubdate字段来过滤显示question:

  过滤器显示的筛选类型取决与你过滤的字段,由于pub_dataDateTimeField,所以Django就自动给出了“今天”、“过去7天”、“本月”、“今年”这几个选项。

  这一切进展顺利。再添加一些搜索功能:

  1. search_fields = ['question_text']

  这行代码在修改列表的顶部添加了一个搜索框。 当进行搜索时,Django将在question_text字段中进行搜索。 你在search_fields中使用任意数量的字段,但由于它在后台使用LIKE进行查询,尽量不要添加太多的字段,不然会降低数据库查询能力。

  修改列表自带分页功能,默认每页展示100条数据。

自定义管理站点外观

  很明显,在每一个admin页面坐上顶端都显示“Django 管理”是感觉很荒诞,它仅仅是个占位文本。利用Django的模板系统,可以易修改它。

  它可以用Django的模板系统轻松改变。 Django的管理站点是用Django自己制作出来的,它的界面代码使用的是Django自己的模板系统。

自定义项目模板

  在项目的路劲下(包含manage.py的目录)创建一个名为templates目录。Templates可以放在你的文件系统中Django所能访问到的任何地方。(运行Web服务器的用户即是运行Django的用户)。然而,但是作为一个好的习惯,最好把模板放在本项目目录下。

  在配置文件中(mysite/settings.py)在TEMPLATES中添加一个DIRS选项:

  1. # mysite/settings.py
  2. TEMPLATES = [
  3. {
  4. 'BACKEND': 'django.template.backends.django.DjangoTemplates',
  5. 'DIRS': [os.path.join(BASE_DIR, 'templates')],
  6. 'APP_DIRS': True,
  7. 'OPTIONS': {
  8. 'context_processors': [
  9. 'django.template.context_processors.debug',
  10. 'django.template.context_processors.request',
  11. 'django.contrib.auth.context_processors.auth',
  12. 'django.contrib.messages.context_processors.messages',
  13. ],
  14. },
  15. },
  16. ]

  DIRS是在加载Django模板时检查的文件系统目录列表;它是一个搜索路径。

模板组织方式:就像静态文件一样,我们可以把所有的模板都放在一起,形成一个大大的模板文件夹,并且工作正常。但是不建议这样!最好每一个模板都应该存放在它所属应用的模板目录内(例如polls/templates)而不是整个项目的模板目录(templates),因为这样每个应用才可以被方便和正确的重用。请参考如何重用apps](https://docs.djangoproject.com/en/1.10/intro/reusable-apps/)。

  接下来,在刚才创建的templates中创建一个admin目录,将admin/base_site.html模板文件拷贝到该目录内。这个html文件来自Django源码,它位于django/contrib/admin/templates目录内。

如何找到Django源文件: 在命令行中运行下面代码: python -c "import django; print(django.__path__)"

  然后替换文件中的{{ site_header|default:_('Django administration') }}(包括两个大括号),换成你想要命名的名字即可。编辑完成后应该类似下面的代码片段:

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

  这里仅仅是使用这种方法来教您如何覆盖模板。在实际的项目中,您可以使用django.contrib.admin.AdminSite。siteheader属性更容易实现这个特殊的定制。

  在这个模板文件中有许多类似这样的文本{% block branding %}{{ title }}{%{{都是Django模板语法的一部分。当Django渲染admin/base_site.html的时候,这个模板语言将被生成最终的html页面,就像Part3中一样。

  注意任何Django管理站点的默认模板都可以重写。 想要重写一个模板文件,只需要做和重写base_site.html相同的操作就行——将它从默认的目录拷贝到你自定义的目录中,然后修改它。

自定义应用模板

  聪明的读者可能会问:但是DIRS默认是空的,Django是如何找到默认的admin模板呢?回答是,由于APP_DIRS被设置为`True``,Django将自动查找每一个应用路径下的templates/子目录(不要忘了django.contrib.admin也是一个应用)。

  我们的投票应用不太复杂,因此不需要自定义admin模板。但是如果它变得越来越复杂,因为某些功能而需要修改Django的标准admin模板,那么修改的模板就比修改项目的模板更加明智。这样的话,你可以将投票应用加入到任何新的项目中,并且保证能够找到它所需要的自定义模板。更多关于Django如何加载模板文件的信息,请查看模板加载 (0%)的文档。

自定义管理站点首页

  在类似的情况下,您可能想要定制Django管理首页页面。默认情况下,管理站点首页显示所有INSTALLED_APPS内并在admin应用中注册过的app,以字母顺序进行排序。

  要定制管理站点首页,需要重写admin/index.html模板,就像前面修改base_site.html模板的方法一样,从源码目录拷贝到你指定的目录内。编辑该文件,你会看到文件内使用了一个app_list模板变量。该变量包含了所有已经安装的Django应用。你可以硬编码链接到指定对象的admin页面,使用任何你认为好的方法,用于替代这个app_list

快速通道

文档地址

Django 1.10中文文档-第一个应用Part7-自定义管理站点的更多相关文章

  1. Django 1.10中文文档-第一个应用Part2-模型和管理站点

    本教程继续Part1.我们将设置数据库,创建您的第一个模型,并快速介绍Django的自动生成的管理网站. 数据库设置 现在,编辑mysite/settings.py.它是一个用模块级别变量表示Djan ...

  2. Django 1.10中文文档-第一个应用Part6-静态文件

    本教程上接Part5 .前面已经建立一个网页投票应用并且测试通过,现在主要讲述如何添加样式表和图片. 除由服务器生成的HTML文件外,网页应用一般还需要提供其它必要的文件——比如图片.JavaScri ...

  3. Django 1.10中文文档-第一个应用Part5-测试

    本教程上接教程Part4. 前面已经建立一个网页投票应用,现在将为它创建一些自动化测试. 自动化测试简介 什么是自动化测试 测试是检查你的代码是否正常运行的行为.测试也分为不同的级别.有些测试可能是用 ...

  4. Django 1.10中文文档-第一个应用Part4-表单和通用视图

    本教程接Part3开始.继续网页投票应用程序,并将重点介绍简单的表单处理和精简代码. 一个简单表单 更新一下在上一个教程中编写的投票详细页面的模板polls/detail.html,让它包含一个HTM ...

  5. Django 1.10中文文档-第一个应用Part3-视图和模板

    本教程上接Django 1.10中文文档-第一个应用Part2-模型和管理站点.我们将继续开发网页投票这个应用,主要讲如何创建一个对用户开放的界面. 概览 视图是Django应用中的一“类”网页,它通 ...

  6. Django 1.10中文文档-第一个应用Part1-请求与响应

    在本教程中,我们将引导您完成一个投票应用程序的创建,它包含下面两部分: 一个可以进行投票和查看结果的公开站点: 一个可以进行增删改查的后台admin管理界面: 我们假设你已经安装了Django.您可以 ...

  7. Django 1.10中文文档—第一个Django应用Part1

    在本教程中,我们将引导您完成一个投票应用程序的创建,它包含下面两部分: 一个可以进行投票和查看结果的公开站点: 一个可以进行增删改查的后台admin管理界面: 我们假设你已经安装了Django.您可以 ...

  8. Django 1.10中文文档-执行查询

    Django 1.10中文文档: https://github.com/jhao104/django-chinese-doc 只要创建好 数据模型, Django 会自动为生成一套数据库抽象的API, ...

  9. Django 1.10中文文档-聚合

    Django 数据库抽象API 描述了使用Django 查询来增删查改单个对象的方法. 然而,有时候你要获取的值需要根据一组对象聚合后才能得到. 这个主题指南描述了如何使用Django的查询来生成和返 ...

随机推荐

  1. BZOJ3594 SCOI2014方伯伯的玉米田(动态规划+树状数组)

    可以发现每次都对后缀+1是不会劣的.考虑dp:设f[i][j]为前i个数一共+1了j次时包含第i个数的LIS长度.则f[i][j]=max(f[i][j-1],f[k][l]+1) (k<i,l ...

  2. 洛谷 P5078 Tweetuzki 爱军训

    题目连接 很明显,1e6的范围,要么nlgn要么O(n) nlgn的话可能会想到借助一些数据结构,我并没有想到这种做法 对于这种题,O(n)的做法要么是线性递推,要么就应该是贪心了 考虑这道题我们怎么 ...

  3. 3294 [SCOI2016]背单词

    题目描述 Lweb 面对如山的英语单词,陷入了深深的沉思,”我怎么样才能快点学完,然后去玩三国杀呢?“.这时候睿智的凤老师从远处飘来,他送给了 Lweb 一本计划册和一大缸泡椒,他的计划册是长这样的: ...

  4. 高rong效chang的可持久化treap

    很多人觉得可持久化treap很慢,但是事实上只是他们可持久化treap的写法不对.他们一般是用split和merge实现所有功能,但是这样会有许多不必要的分裂.其实我们可以用一种特殊的方式来实现插入和 ...

  5. 【刷题】BZOJ 4025 二分图

    Description 神犇有一个n个节点的图.因为神犇是神犇,所以在T时间内一些边会出现后消失.神犇要求出每一时间段内这个图是否是二分图.这么简单的问题神犇当然会做了,于是他想考考你. Input ...

  6. 如何用Qt Python创建简单的桌面条形码应用

    Qt for Python可以快速跨平台的GUI应用.这篇文章分享下如何结合Dynamsoft Barcode Reader SDK来创建一个简单的读码应用. 安装Qt for Python 官方站点 ...

  7. 解决:warning LNK4098: 默认库“MSVCRT”与其他库的使用冲突;找到 MSIL .netmodule 或使用 /GL 编译的模块;正在。。;LINK : warning LNK4075: 忽略“/INCREMENTAL”(由于“/LTCG”规范)

    原文链接地址:https://www.cnblogs.com/qrlozte/p/4844411.html 参考资料: http://blog.csdn.net/laogaoav/article/de ...

  8. 温习classList api

    有道题是一个removeClass的功能,代码里是正则分隔了传入的name,根据name的个数,循环移除掉,让寻找bug..看了了这几行代码,首先想到的是我会如何去优化. 如果看代码一两分钟就能找到公 ...

  9. 【乱搞】【CF1095E】 Almost Regular Bracket Sequence

    Description 给定一个长度为 \(n\) 的小括号序列,求有多少个位置满足将这个位置的括号方向反过来后使得新序列是一个合法的括号序列.即在任意一个位置前缀左括号的个数不少于前缀右括号的个数, ...

  10. struts的status属性

    struts2 <s:iterator> status属性 转载▼   iterator标签主要是用于迭代输出集合元素,如list set map 数组等,在使用标签的时候有三个属性值得我 ...