第六章 Django站点管理

第六章 Django站点管理

对于某一类网站, 管理界面 是基础设施中很是重要的一部分。 这是以网页和有限的可信任管理者为基础的界面,它可让你添加,编辑和删除网站内容。 一些常见的例子: 你能够用这个界面发布博客,后台的网站管理者用它来润色读者提交的内容,你的客户用你给他们创建的界面工具更新新闻并发布在网站上,这些都是使用管理界面的例子。python

可是管理界面有一问题: 建立它太繁琐。 当你开发对公众的功能时,网页开发是有趣的,可是建立管理界面一般是千篇一概的。 你必须认证用户,显示并管理表格,验证输入的有效性诸如此类。 这很繁琐并且是重复劳动。程序员

Django 在对这些繁琐和重复的工做进行了哪些改进? 它用不能再少的代码为你作了全部的一切。 Django 中建立管理界面已经不是问题。shell

这一章是关于 Django 的自动管理界面。 这个特性是这样起做用的: 它读取你模式中的元数据,而后提供给你一个强大并且可使用的界面,网站管理者能够用它当即工做。数据库

请注意咱们建议你读这章,即便你不打算用admin。由于咱们将介绍一些概念,这些概念能够应用到Django的全部方面,而不只仅是admindjango

django.contrib 包

Django自动管理工具是django.contrib的一部分。django.contrib是一套 庞大的功能集,它是Django基本代码的组成部分,Django框架就是由众多包含附加组件(add-on)的基本代码构成的。 你能够把django.contrib看做是可选的Python标准库或广泛模式的实际实现。 它们与Django捆绑在一块儿,这样你在开发中就不用“重复发明轮子”了。编程

管理工具是本书讲述django.contrib的第一个部分。从技术层面上讲,它被称做 django.contrib.admin。django.contrib中其它可用的特性,如用户鉴别系统 (django.contrib.auth)、支持匿名会话(django.contrib.sessioins)以及用户评注系统 (django.contrib.comments)。这些,咱们将在第十六章详细讨论。在成为一个Django专家之前,你将会知道更多 django.contrib的特性。 目前,你只须要知道Django自带不少优秀的附加组件,它们都存在于django.contrib包里。浏览器

激活管理界面

Django管理站点彻底是可选择的,由于仅仅某些特殊类型的站点才须要这些功能。 这意味着你须要在你的项目中花费几个步骤去激活它。服务器

第一步,对你的settings文件作以下这些改变:网络

  1. 'django.contrib.admin'加入setting的INSTALLED_APPS配置中 (INSTALLED_APPS中的配置顺序是没有关系的, 可是咱们喜欢保持必定顺序以方便人来阅读)session

  2. 保证INSTALLED_APPS中包含'django.contrib.auth''django.contrib.contenttypes''django.contrib.sessions',Django的管理工具须要这3个包。 (若是你跟随本文制做mysite项目的话,那么请注意咱们在第五章的时候把这三项INSTALLED_APPS条目注释了。如今,请把注释取消。)

  3. 确保MIDDLEWARE_CLASSES 包含'django.middleware.common.CommonMiddleware' 、'django.contrib.sessions.middleware.SessionMiddleware' 和'django.contrib.auth.middleware.AuthenticationMiddleware' 。(再次提醒,若是有跟着作mysite的话,请把在第五章作的注释取消。)

运行 python manage.py syncdb 。这一步将生成管理界面使用的额外数据库表。 当你把'django.contrib.auth'加进INSTALLED_APPS后,第一次运行syncdb命令时, 系统会请你建立一个超级用户。 若是你不这么做,你须要运行python manage.py createsuperuser来另外建立一个admin的用户账号,不然你将不能登入admin (提醒一句: 只有当INSTALLED_APPS包含'django.contrib.auth'时,python manage.py createsuperuser这个命令才可用.)

第三,将admin访问配置在URLconf(记住,在urls.py中). 默认状况下,命令django-admin.py startproject生成的文件urls.py是将Django admin的路径注释掉的,你所要作的就是取消注释。 请注意,如下内容是必须确保存在的:

# Include these import statements...
from django.contrib import admin
admin.autodiscover()

# And include this URLpattern...
urlpatterns = patterns('',
    # ...
    (r'^admin/', include(admin.site.urls)),
    # ...
)

当这一切都配置好后,如今你将发现Django管理工具能够运行了。 启动开发服务器(如前:`` python manage.py runserver`` ),而后在浏览器中访问:http://127.0.0.1:8000/admin/

,使用管理工具。

管理界面的设计是针对非技术人员的,因此它应该是自我解释的。 尽管如此,这里简单介绍一下它的基本特性。

你看到的第一件事是如图6-1所示的登陆屏幕。

Django 登陆页面的截图。

图 6-1. Django的登陆截图

你要使用你原来设置的超级用户的用户名和密码。 若是没法登陆,请运行`` python manage.py createsuperuser`` ,确保你已经建立了一个超级用户。

一旦登陆了,你将看到管理页面。 这个页面列出了管理工具中可编辑的全部数据类型。 如今,因为咱们尚未建立任何模块,因此这个列表只有寥寥数条类目: 它仅有两个默认的管理-编辑模块:用户组(Groups)和用户(Users)。

Django 主管理索引截图。

图 6-2。 Django admin的首页

在Django管理页面中,每一种数据类型都有一个* change list* 和* edit form* 。前者显示数据库中全部的可用对象;后者可以让你添加、更改和删除数据库中的某条记录。

其它语言

若是你的母语不是英语,而你不想用它来配置你的浏览器,你能够作一个快速更改来观察Django管理工 具是否被翻译成你想要的语言。 仅需添加`` ‘django.middleware.locale.LocaleMiddleware’`` 到`` MIDDLEWARE_CLASSES`` 设置中,并确保它在’django.contrib.sessions.middleware.SessionMiddleware’* 以后* 。 (见上)

完成后,请刷新页面。 若是你设置的语言可用,一系列的连接文字将被显示成这种语言。这些文字包括页面顶端的Change password和Log out,页面中部的Groups和Users。 Django自带了多种语言的翻译。

关于Django更多的国际化特性,请参见第十九章。

点击Uers行中的Change连接,引导用户更改列表。

修改过的变动列表页面截图。

图 6-3. 典型的改变列表视图 (见上)

这个页面显示了数据库中全部的用户。你能够将它看做是一个漂亮的网页版查询:`` SELECT * FROM auth_user;`` 若是你一直跟着做练习,而且只添加了一个用户,你会在这个页面中看到一个用户。可是若是你添加了多个用户,你会发现页面中还有过滤器、排序和查询框。 过滤器在右边;排序功能可经过点击列头查看;查询框在页面顶部,它容许你经过用户名查询。

点击其中一个用户名,你会看见关于这个用户的编辑窗口。

典型的编辑表格截图。

图 6-4. 典型的编辑表格 (见上)

这个页面容许你修改用户的属性,如姓名和权限。 (若是要更改用户密码,你必须点击密码字段下的change password form,而不是直接更改字段值中的哈西码。)另外须要注意的是,不一样类型的字段会用不一样的窗口控件显示。例如,日期/时间型用日历控件,布尔型用复选 框,字符型用简单文本框显示。

你能够经过点击编辑页面下方的删除按钮来删除一条记录。 你会见到一个确认页面。有时候,它会显示有哪些关联的对象将会一并被删除。 (例如,若是你要删除一个出版社,它下面全部的图书也将被删除。)

你能够经过点击管理主页面中某个对象的Add来添加一条新记录。 一个空白记录的页面将被打开,等待你填充。

你还能看到管理界面也控制着你输入的有效性。 你能够试试不填必需的栏目或者在时间栏里填错误的时间,你会发现当你要保存时会出现错误信息,如图6-5所示。

编辑表格显示错误信息的截图。

图6-5. 编辑表格显示错误信息 (见上)

当你编辑已有的对像时,你在窗口的右上角能够看到一个历史按钮。 经过管理界面作的每个改变都留有记录,你能够按历史键来检查这个记录(见图6-6)。

Django 历史页面截图。

图6-6. Django 对像历史页面 (见上)

将你的Models加入到Admin管理中

有一个关键步骤咱们还没作。 让咱们将本身的模块加入管理工具中,这样咱们就可以经过这个漂亮的界面添加、修改和删除数据库中的对象了。 咱们将继续第五章中的`` book`` 例子。在其中,咱们定义了三个模块: Publisher 、 Author 和 Book 。

在`` books`` 目录下(`` mysite/books`` ),建立一个文件:`` admin.py`` ,而后输入如下代码:

from django.contrib import admin
from mysite.books.models import Publisher, Author, Book

admin.site.register(Publisher)
admin.site.register(Author)
admin.site.register(Book)

这些代码通知管理工具为这些模块逐一提供界面。

完成后,打开页面 `` http://127.0.0.1:8000/admin/`` ,你会看到一个Books区域,其中包含Authors、Books和Publishers。  (你可能须要先中止,而后再启动服务(`` runserver`` ),才能使其生效。)

如今你拥有一个功能完整的管理界面来管理这三个模块了。 很简单吧!

花点时间添加和修改记录,以填充数据库。 若是你跟着第五章的例子一块儿建立Publisher对象的话(而且没有删除),你会在列表中看到那些记录。

这里须要提到的一个特性是,管理工具处理外键和多对多关系(这两种关系能够在`` Book`` 模块中找到)的方法。 做为提醒,这里有个`` Book`` 模块的例子:

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField()

    def __unicode__(self):
        return self.title

在Add book页面中(`` http://127.0.0.1:8000/admin/books/book/add/`` ),`` 外键`` publisher用一个选择框显示,`` 多对多`` 字段author用一个多选框显示。 点击两个字段后面的绿色加号,可让你添加相关的记录。 举个例子,若是你点击Publisher后面的加号,你将会获得一个弹出窗口来添加一个publisher。 当你在那个窗口中成功建立了一个publisher后,Add book表单会自动把它更新到字段上去 花巧.

Admin是如何工做的

在幕后,管理工具是如何工做的呢? 其实很简单。

当服务启动时,Django从`` url.py`` 引导URLconf,而后执行`` admin.autodiscover()`` 语句。 这个函数遍历INSTALLED_APPS配置,而且寻找相关的 admin.py文件。 若是在指定的app目录下找到admin.py,它就执行其中的代码。

在`` books`` 应用程序目录下的`` admin.py`` 文件中,每次调用`` admin.site.register()`` 都将那个模块注册到管理工具中。 管理工具只为那些明确注册了的模块显示一个编辑/修改的界面。

应用程序`` django.contrib.auth`` 包含自身的`` admin.py`` ,因此Users和Groups能在管理工具中自动显示。 其它的django.contrib应用程序,如django.contrib.redirects,其它从网上下在的第三方Django应用程序同样,都会自行添加到管理工具。

综上所述,管理工具其实就是一个Django应用程序,包含本身的模块、模板、视图和URLpatterns。 你要像添加本身的视图同样,把它添加到URLconf里面。 你能够在Django基本代码中的django/contrib/admin目录下,检查它的模板、视图和URLpatterns,但你不要尝试直接修改其中的任何代码,由于里面有不少地方可让你自定义管理工具的工做方式。 (若是你确实想浏览Django管理工具的代码,请谨记它在读取关于模块的元数据过程当中作了些不简单的工做,所以最好花些时间阅读和理解那些代码。)

设置字段可选

在摆弄了一会以后,你或许会发现管理工具备个限制:编辑表单须要你填写每个字段,然而在有些状况下,你想要某些字段是可选的。 举个例子,咱们想要Author模块中的email字段成为可选,即容许不填。 在现实世界中,你可能没有为每一个做者登记邮箱地址。

为了指定email字段为可选,你只要编辑Book模块(回想第五章,它在mysite/books/models.py文件里),在email字段上加上blank=True。代码以下:

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField(**blank=True** )

这些代码告诉Django,做者的邮箱地址容许输入一个空值。 全部字段都默认blank=False,这使得它们不容许输入空值。

这里会发生一些有趣的事情。 直到如今,除了__unicode__()方法,咱们的模块充当数据库中表定义的角色,即本质上是用Python的语法来写CREATE TABLE语句。 在添加blank=True过程当中,咱们已经开始在简单的定义数据表上扩展咱们的模块了。 如今,咱们的模块类开始成为一个富含Author对象属性和行为的集合了。 email不但展示为一个数据库中的VARCHAR类型的字段,它仍是页面中可选的字段,就像在管理工具中看到的那样。

当你添加blank=True之后,刷新页面Add author edit form (http://127.0.0.1:8000/admin/books/author/add/ ),将会发现Email的标签再也不是粗体了。 这意味它不是一个必填字段。 如今你能够添加一个做者而没必要输入邮箱地址,即便你为这个字段提交了一个空值,也再不会获得那刺眼的红色信息“This field is required”。

设置日期型和数字型字段可选

虽然blank=True一样适用于日期型和数字型字段,可是这里须要详细讲解一些背景知识。

SQL有指定空值的独特方式,它把空值叫作NULL。NULL能够表示为未知的、非法的、或其它程序指定的含义。

在SQL中, NULL的值不一样于空字符串,就像Python中None不一样于空字符串("")同样。这意味着某个字符型字段(如VARCHAR)的值不可能同时包含NULL和空字符串。

这会引发没必要要的歧义或疑惑。 为何这条记录有个NULL,而那条记录却有个空字符串? 它们之间有区别,仍是数据输入不一致? 还有: 我怎样才能获得所有拥有空值的记录,应该按NULL和空字符串查找么?仍是仅按字符串查找?

为了消除歧义,Django生成CREATE TABLE语句自动为每一个字段显式加上NOT NULL。 这里有个第五章中生成Author模块的例子:

CREATE TABLE "books_author" (
    "id" serial NOT NULL PRIMARY KEY,
    "first_name" varchar(30) NOT NULL,
    "last_name" varchar(40) NOT NULL,
    "email" varchar(75) NOT NULL
)
;

在大多数状况下,这种默认的行为对你的应用程序来讲是最佳的,由于它可使你再也不因数据一致性而头痛。 并且它能够和Django的其它部分工做得很好。如在管理工具中,若是你留空一个字符型字段,它会为此插入一个空字符串(而* 不是*NULL)。

可是,其它数据类型有例外:日期型、时间型和数字型字段不接受空字符串。 若是你尝试将一个空字符串插入日期型或整数型字段,你可能会获得数据库返回的错误,这取决于那个数据库的类型。 (PostgreSQL比较严禁,会抛出一个异常;MySQL可能会也可能不会接受,这取决于你使用的版本和运气了。)在这种状况下,NULL是惟一指定空值的方法。 在Django模块中,你能够经过添加null=True来指定一个字段容许为NULL

所以,这提及来有点复杂: 若是你想容许一个日期型(DateFieldTimeFieldDateTimeField)或数字型(IntegerFieldDecimalFieldFloatField)字段为空,你须要使用null=True * 和* blank=True

为了举例说明,让咱们把Book模块修改为容许 publication_date为空。修改后的代码以下:

class Book(models.Model):
    title = models.CharField(max_length=100)
    authors = models.ManyToManyField(Author)
    publisher = models.ForeignKey(Publisher)
    publication_date = models.DateField(**blank=True, null=True** )

添加null=True比添加blank=True复杂。由于null=True改变了数据的语义,即改变了CREATE TABLE语句,把publication_date字段上的NOT NULL删除了。 要完成这些改动,咱们还须要更新数据库。

出于某种缘由,Django不会尝试自动更新数据库结构。因此你必须执行ALTER TABLE语句将模块的改动更新至数据库。 像先前那样,你可使用manage.py dbshell进入数据库服务环境。 如下是在这个特殊状况下如何删除NOT NULL:

ALTER TABLE books_book ALTER COLUMN publication_date DROP NOT NULL;

(注意:如下SQL语法是PostgreSQL特有的。)

咱们将在第十章详细讲述数据库结构更改。

如今让咱们回到管理工具,添加book的编辑页面容许输入一个空的publication date。

自定义字段标签

在编辑页面中,每一个字段的标签都是从模块的字段名称生成的。 规则很简单: 用空格替换下划线;首字母大写。例如:Book模块中publication_date的标签是Publication date。

然而,字段名称并不老是贴切的。有些状况下,你可能想自定义一个标签。 你只需在模块中指定verbose_name

举个例子,说明如何将Author.email的标签改成e-mail,中间有个横线。

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField(blank=True, **verbose_name='e-mail'** )

修改后重启服务器,你会在author编辑页面中看到这个新标签。

请注意,你没必要把verbose_name的首字母大写,除非是连续大写(如:"USA state")。Django会自动适时将首字母大写,而且在其它不须要大写的地方使用verbose_name的精确值。

最后还需注意的是,为了使语法简洁,你能够把它看成固定位置的参数传递。 这个例子与上面那个的效果相同。

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField(**'e-mail',**  blank=True)

但这不适用于ManyToManyField 和ForeignKey字段,由于它们第一个参数必须是模块类。 那种情形,必须显式使用verbose_name这个参数名称。

自定义ModelAdmi类

迄今为止,咱们作的blank=Truenull=Trueverbose_name修改实际上是模块级别,而不是管理级别的。 也就是说,这些修改实质上是构成模块的一部分,而且正好被管理工具使用,而不是专门针对管理工具的。

除了这些,Django还提供了大量选项让你针对特别的模块自定义管理工具。 这些选项都在ModelAdmin classes里面,这些类包含了管理工具中针对特别模块的配置。

自定义列表

让咱们更深一步:自定义Author模块的列表中的显示字段。 列表默认地显示查询结果中对象的__unicode__()。 在第五章中,咱们定义Author对象的__unicode__()方法,用以同时显示做者的姓和名。

class Author(models.Model):
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=40)
    email = models.EmailField(blank=True, verbose_name='e-mail')

    **def __unicode__(self):**
        **return u'%s %s' % (self.first_name, self.last_name)**

结果正如图6-7所示,列表中显示的是每一个做者的姓名。

Screenshot of the author change list page.

图 6-7. 做者列表

咱们能够在这基础上改进,添加其它字段,从而改变列表的显示。 这个页面应该提供便利,好比说:在这个列表中能够看到做者的邮箱地址。若是能按照姓氏或名字来排序,那就更好了。

为了达到这个目的,咱们将为Author模块定义一个ModelAdmin类。 这个类是自定义管理工具的关键,其中最基本的一件事情是容许你指定列表中的字段。 打开admin.py并修改:

from django.contrib import admin
from mysite.books.models import Publisher, Author, Book

**class AuthorAdmin(admin.ModelAdmin):**
    **list_display = ('first_name', 'last_name', 'email')**

admin.site.register(Publisher)
**admin.site.register(Author, AuthorAdmin)**
admin.site.register(Book)

解释一下代码:

咱们新建了一个类AuthorAdmin,它是从django.contrib.admin.ModelAdmin派生出来的子类,保存着一个类的自定义配置,以供管理工具使用。 咱们只自定义了一项:list_display, 它是一个字段名称的元组,用于列表显示。 固然,这些字段名称必须是模块中有的。

咱们修改了admin.site.register()调用,在Author后面添加了AuthorAdmin。你能够这样理解: 用AuthorAdmin选项注册Author模块。

admin.site.register()函数接受一个ModelAdmin子类做为第二个参数。 若是你忽略第二个参数,Django将使用默认的选项。PublisherBook的注册就属于这种状况。

弄好了这个东东,再刷新author列表页面,你会看到列表中有三列:姓氏、名字和邮箱地址。 另外,点击每一个列的列头能够对那列进行排序。 (参见图 6-8)

Screenshot of the author change list page after list_display.

图 6-8. 修改后的author列表页面

接下来,让咱们添加一个快速查询栏。 向AuthorAdmin追加search_fields,如:

class AuthorAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'email')
    **search_fields = ('first_name', 'last_name')**

刷新浏览器,你会在页面顶端看到一个查询栏。 (见图6-9.)咱们刚才所做的修改列表页面,添加了一个根据姓名查询的查询框。 正如用户所但愿的那样,它是大小写敏感,而且对两个字段检索的查询框。若是查询"bar",那么名字中含有Barney和姓氏中含有Hobarson的做者记录将被检索出来。

Screenshot of the author change list page after search_fields.

图 6-9. 含search_fields的author列表页面

接下来,让咱们为Book列表页添加一些过滤器。

from django.contrib import admin
from mysite.books.models import Publisher, Author, Book

class AuthorAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'email')
    search_fields = ('first_name', 'last_name')

**class BookAdmin(admin.ModelAdmin):**
    **list_display = ('title', 'publisher', 'publication_date')**
    **list_filter = ('publication_date',)**

admin.site.register(Publisher)
admin.site.register(Author, AuthorAdmin)
**admin.site.register(Book, BookAdmin)**

因为咱们要处理一系列选项,所以咱们建立了一个单独的ModelAdmin类:BookAdmin。首先,咱们定义一个list_display,以使得页面好看些。 而后,咱们用list_filter这个字段元组建立过滤器,它位于列表页面的右边。 Django为日期型字段提供了快捷过滤方式,它包含:今天、过往七天、当月和今年。这些是开发人员常常用到的。 图 6-10显示了修改后的页面。

Screenshot of the book change list page after list_filter.

图 6-10. 含过滤器的book列表页面

`` 过滤器`` 一样适用于其它类型的字段,而不单是`` 日期型`` (请在`` 布尔型`` 和`` 外键`` 字段上试试)。当有两个以上值时,过滤器就会显示。

另一种过滤日期的方式是使用date_hierarchy选项,如:

class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'publisher', 'publication_date')
    list_filter = ('publication_date',)
    **date_hierarchy = 'publication_date'**

修改好后,页面中的列表顶端会有一个逐层深刻的导航条,效果如图 6-11. 它从可用的年份开始,而后逐层细分到月乃至日。

Screenshot of the book change list page after date_hierarchy.

图 6-11. 含date_hierarchy的book列表页面

请注意,date_hierarchy接受的是* 字符串* ,而不是元组。由于只能对一个日期型字段进行层次划分。

最后,让咱们改变默认的排序方式,按publication date降序排列。 列表页面默认按照模块class Meta(详见第五章)中的ordering所指的列排序。但目前没有指定ordering值,因此当前排序是没有定义的。

class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'publisher', 'publication_date')
    list_filter = ('publication_date',)
    date_hierarchy = 'publication_date'
    **ordering = ('-publication_date',)**

这个ordering选项基本像模块中class Metaordering那样工做,除了它只用列表中的第一个字段名。 若是要实现降序,仅需在传入的列表或元组的字段前加上一个减号(-)。

刷新book列表页面观看实际效果。 注意Publication date列头如今有一个小箭头显示排序。 (见图 6-12.)

Screenshot of the book change list page after ordering.

图 6-12 含排序的book列表页面

咱们已经学习了主要的选项。 经过使用它们,你能够仅需几行代码就能建立一个功能强大、随时上线的数据编辑界面。

自定义编辑表单

正如自定义列表那样,编辑表单多方面也能自定义。

首先,咱们先自定义字段顺序。 默认地,表单中的字段顺序是与模块中定义是一致的。 咱们能够经过使用ModelAdmin子类中的fields选项来改变它:

class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'publisher', 'publication_date')
    list_filter = ('publication_date',)
    date_hierarchy = 'publication_date'
    ordering = ('-publication_date',)
    **fields = ('title', 'authors', 'publisher', 'publication_date')**

完成以后,编辑表单将按照指定的顺序显示各字段。 它看起来天然多了——做者排在书名以后。 字段顺序固然是与数据条目录入顺序有关, 每一个表单都不同。

经过fields这个选项,你能够排除一些不想被其余人编辑的fields 只要不选上不想被编辑的field(s)便可。 当你的admi用户只是被信任能够更改你的某一部分数据时,或者,你的数据被一些外部的程序自动处理而改变了了,你就能够用这个功能。 例如,在book数据库中,咱们能够隐藏publication_date,以防止它被编辑。

class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'publisher', 'publication_date')
    list_filter = ('publication_date',)
    date_hierarchy = 'publication_date'
    ordering = ('-publication_date',)
    **fields = ('title', 'authors', 'publisher')**

这样,在编辑页面就没法对publication date进行改动。 若是你是一个编辑,不但愿做者推迟出版日期的话,这个功能就颇有用。 (固然,这纯粹是一个假设的例子。)

当一个用户用这个不包含完整信息的表单添加一本新书时,Django会简单地将publication_date设置为None,以确保这个字段知足null=True的条件。

另外一个经常使用的编辑页面自定义是针对多对多字段的。 真如咱们在book编辑页面看到的那样,`` 多对多字段`` 被展示成多选框。虽然多选框在逻辑上是最适合的HTML控件,但它却不那么好用。 若是你想选择多项,你必须还要按下Ctrl键(苹果机是command键)。 虽然管理工具所以添加了注释(help_text),可是当它有几百个选项时,它依然显得笨拙。

更好的办法是使用filter_horizontal。让咱们把它添加到BookAdmin中,而后看看它的效果。

class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'publisher', 'publication_date')
    list_filter = ('publication_date',)
    date_hierarchy = 'publication_date'
    ordering = ('-publication_date',)
    **filter_horizontal = ('authors',)**

(若是你一着跟着作练习,请注意移除fields选项,以使得编辑页面包含全部字段。)

刷新book编辑页面,你会看到Author区中有一个精巧的JavaScript过滤器,它容许你检索选项,而后将选中的authors从Available框移到Chosen框,还能够移回来。

Screenshot of the book edit form after adding filter_horizontal.

图 6-13. 含filter_horizontal的book编辑页面

咱们强烈建议针对那些拥有十个以上选项的`` 多对多字段`` 使用filter_horizontal。 这比多选框好用多了。 你能够在多个字段上使用filter_horizontal,只需在这个元组中指定每一个字段的名字。

ModelAdmin类还支持filter_vertical选项。 它像filter_horizontal那样工做,除了控件都是垂直排列,而不是水平排列的。 至于使用哪一个,只是我的喜爱问题。

filter_horizontalfilter_vertical选项只能用在多对多字段 上, 而不能用于 ForeignKey字 段。 默认地,管理工具使用`` 下拉框`` 来展示`` 外键`` 字段。可是,正如`` 多对多字段`` 那样,有时候你不想忍受因装载并显示这些选项而产生的大量开销。 例如,咱们的book数据库膨胀到拥有数千条publishers的记录,以至于book的添加页面装载时间较久,由于它必须把每个publishe都 装载并显示在`` 下拉框`` 中。

解决这个问题的办法是使用`` raw_id_fields`` 选项。它是一个包含外键字段名称的元组,它包含的字段将被展示成`` 文本框`` ,而再也不是`` 下拉框`` 。见图 6-14。

class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'publisher', 'publication_date')
    list_filter = ('publication_date',)
    date_hierarchy = 'publication_date'
    ordering = ('-publication_date',)
    filter_horizontal = ('authors',)
    **raw_id_fields = ('publisher',)**

Screenshot of edit form after raw_id_fields.

图 6-14. 含raw_id_fields的book编辑页面

在这个输入框中,你输入什么呢? publisher的数据库ID号。 考虑到人们一般不会记住这些数据库ID,管理工具提供了一个放大镜图标方便你输入。点击那个图标将会弹出一个窗口,在那里你能够选择想要添加的publishe。

用户、用户组和权限

由于你是用超级用户登陆的,你能够建立,编辑和删除任何对像。 然而,不一样的环境要求有不一样的权限,系统不容许全部人都是超级用户。 管理工具备一个用户权限系统,经过它你能够根据用户的须要来指定他们的权限,从而达到部分访问系统的目的。

用户账号应该是通用的、独立于管理界面之外仍可使用。但咱们如今把它看做是管理界面的一部分。 在第十四章,咱们将讲述如何把用户账号与你的网站(不只仅是管理工具)集成在一块儿。

你经过管理界面编辑用户及其许可就像你编辑别的对象同样。 咱们在本章的前面,浏览用户和用户组区域的时候已经见过这些了。 如你所想,用户对象有标准的用户名、密码、邮箱地址和真实姓名,同时它还有关于使用管理界面的权限定义。 首先,这有一组三个布尔型标记:

  • 活动标志,它用来控制用户是否已经激活。 若是一个用户账号的这个标记是关闭状态,而用户又尝试用它登陆时,即便密码正确,他也没法登陆系统。

  • 成员标志,它用来控制这个用户是否能够登陆管理界面(即:这个用户是否是大家组织里的成员) 因为用户系统能够被用于控制公众页面(即:非管理页面)的访问权限(详见第十四章),这个标志可用来区分公众用户和管理用户。

  • 超级用户标志,它赋予用户在管理界面中添加、修改和删除任何项目的权限。 若是一个用户账号有这个标志,那么全部权限设置(即便没有)都会被忽略。

普通的活跃,非超级用户的管理用户能够根据一套设定好的许可进入。 管理界面中每种可编辑的对象(如:books、authors、publishers)都有三种权限: 建立 许可, 编辑 许可和 删除 许可。 给一个用户受权许可也就代表该用户能够进行许可描述的操做。

当你建立一个用户时,它没有任何权限,该有什么权限是由你决定的。 例如,你能够给一个用户添加和修改publishers的权限,而不给他删除的权限。 请注意,这些权限是定义在模块级别上,而不是对象级别上的。据个例子,你可让小强修改任何图书,可是不能让他仅修改由机械工业出版社出版的图书。 后面这种基于对象级别的权限设置比较复杂,而且超出了本书的覆盖范围,但你能够在Django documentation中寻找答案。

注释

权限管理系统也控制编辑用户和权限。 若是你给某人编辑用户的权限,他能够编辑本身的权限,这种能力可能不是你但愿的。 赋予一个用户修改用户的权限,本质上说就是把他变成一个超级用户。

你也能够给组中分配用户。 一个  简化了给组中全部成员应用一套许可的动做。 组在给大量用户特定权限的时候颇有用。

什么时候、为何使用管理界面?什么时候又不使用呢?

通过这一章的学习,你应该对Django管理工具备所认识。 可是咱们须要代表一个观点:* 何时* 、* 为何* 用,以及何时又* 不* 用。

Django的管理界面对非技术用户要输入他们的数据时特别有用;事实上这个特性就是专门为这个 实现的。 在Django最开始开发的新闻报道的行业应用中,有一个典型的在线自来水的水质专题报道 应用,它的实现流程是这样的:

  • 负责这个报道的记者和要处理数据的开发者碰头,提供一些数据给开发者。

  • 开发者围绕这些数据设计模型而后配置一个管理界面给记者。

  • 记者检查管理界面,尽早指出缺乏或多余的字段。 开发者来回地修改模块。

  • 当模块承认后,记者就开始用管理界面输入数据。 同时,程序员能够专一于开发公众访问视图和模板(有趣的部分)。

换句话说,Django的管理界面为内容输入人员和编程人员都提供了便利的工具。

固然,除了数据输入方面,咱们发现管理界面在下面这些情景中也是颇有用的:

    • 检查模块* :当你定义好了若干个模块,在管理页面中把他们调出来而后输入一些虚假的数据,这是至关有用的。 有时候,它能显示数据建模的错误或者模块中其它问题。

    • 管理既得数据* :若是你的应用程序依赖外部数据(来自用户输入或网络爬虫),管理界面提供了一个便捷的途径,让你检查和编辑那些数据。 你能够把它看做是一个功能不那么强大,可是很方便的数据库命令行工具。

    • 临时的数据管理程序* :你能够用管理工具创建本身的轻量级数据管理程序,好比说开销记录。 若是你正在根据本身的,而不是公众的须要开发些什么,那么管理界面能够带给你很大的帮助。 从这个意义上讲,你能够把它看做是一个加强的关系型电子表格。

最后一点要澄清的是: 管理界面不是终结者。 过往许多年间,咱们看到它被拆分、修改为若干个功能模块,而这些功能不是它所支持的。 它不该成为一个* 公众* 数据访问接口,也不该容许对你的数据进行复杂的排序和查询。 正如本章开头所说,它仅提供给可信任的管理员。 请记住这一点,它是有效使用管理界面的钥匙。

相关文章
相关标签/搜索