第 17 章 扩展 Django 管理界面

优质
小牛编辑
133浏览
2023-12-01

第六章介绍了 Django 的管理界面,现在是该回过头来仔细了解一下的时候了。

正如我们之前多次提到过的,Django 的管理界面是该框架的杀手级特性之一,多数 Django开发人员都知道它既省时又好用。由于该管理界面极受欢迎,对 Django 开发人员来说,想对它进行定制和拓展是件很平常的事情。

第六章的最后几节介绍了定制部分管理界面的一些简单方法。进入本章之前,请先复习一下那部分资料;其中涵盖了如何定制管理接口的 change list 和 edit forms ,以及如何将管理界面冠以与站点一致的风格。

第六章还讨论了何时以及如何使用管理界面,由于那些资料对本章剩下内容是个好的起点,在此我们将重温一遍:

显而易见,对数据编辑工作来说,该管理界面极为有用(想象一下)。如果用于完成某种数据的录入工作,该管理界面实在是无人能及。我们猜想本书绝大多数读者都有成堆数据录入任务。

Django 管理接口特别关注那些没有技术背景的用户来使用数据录入;这也是该功能的开发目的。在 Django 最初开发地报社,开发一个典型的在线市政供水质量报告系统,需求如下:

  • 负责该题材的记者与某个开发人员会面,提交现有数据。

  • 开发人员围绕该数据设计一个模型,并为该记者开发出管理界面。

  • 在记者将数据录入 Django 的同时,程序员就可以专注于开发公众访问界面了(最有趣的部分!)。

    换句话说,Django 管理接口之所以存在的首要目的是为了方便内容编辑人员和程序员同时开展工作。

    当然,除了显而易见的数据录入任务之外,我们发现管理界面在其他一些情况下有是很有用处的。

  • 查验数据模型 : 定义好一个新的数据模型以后,我们要做的第一件事情就是在管理界面中将它运行起来,然后输入一些假想数据。通常在发现数据建模出错后,用图形化的模型界面可以快速找到症结所在。

  • 管理获得的数据 :很少有真实数据输入会和像 http://chicagocrime.org 这样的站点相关联,因为多数数据来自自动生成的源头。然而,当所获取的数据出错而导致麻烦时,能够便捷地找到并修改出错数据将会有助于问题解决。

    无需或者仅需略为定制之后, Django 管理界面就能处理绝大部分常见情形。然而,正是因为在设计上极力折衷, Django 管理界面能够很好地处理这种常见情形也就意味着它无法同样处理其它一些编辑模型。

    稍后,我们将讨论哪些 不是 Django 管理界面设计用来处置的情形,但首先让我们暂时岔开话题,讨论一下它的设计理念。

    管理之道

    在核心部分,Django 管理界面只被设计用于一种行为:受信任用户编辑结构化的内容。

    是的,这非常的简单,但这种简单是建立在一整堆假定之上的。Django 管理界面的全部设计理念均直接遵循这些假定,因此让我们深入理解一下这些后续小节中所出现术语的含义。

    受信任用户

    管理界面被设计成由你这样的开发人员所 信任 的人使用。这里所指的并非只是通过身份验证的人;而是说 Django 假定可以相信内容编辑者只会做对的事情。

    反过来说,这也就意味着如果你信任用户,他们无需征得许可就能编辑内容,也没有人需要对他们的编辑行为 进行许可。另一层含义是,尽管认证系统功能强大,但到本书写作时为止,它并不支持对象级基础的访问限制。如果你允许某人对自己的新闻报道进行编辑,你必须 能够确信该用户不会未经许可对其他人的报道进行编辑。

    编辑

    Django 管理界面的首要目的是让用户编辑数据。乍一看这是显而易见的,但仔细一想却又变得有点难以捉摸和不同凡响。

    举例来说,虽然管理界面非常便于查验数据(如刚才所讨论的那样),但这并不是它的设计初衷。比如我们在第 12 章中谈到的,它缺少视图许可。Django 假定如果某人在管理界面中可以查看内容,那么也可以进行编辑。

    还有件更重要的事情要注意,那就是对于远程调用工作流的缺乏。如果某个特定任务由一系列步骤组成,没有任何机制确保这些步骤能够以某个特定顺序完成。 Django 管理界面专注于 编辑 ,而不关心修改周边的活动。对工作流的这种回避也源自于信任原则:管理界面的设计理念是工作流乃人为事物,无需在代码中实现。

    最后,要注意的是管理界面中缺少聚合。也就是说,不支持显示总计、平均值之类的东西。再次重申,管理界面只用于编辑——它预期你将通过定义视图来完成其它所有工作。

    结构化的内容

    在 Django 其它部分配合下,管理界面希望你使用结构化的数据。因此,它只支持存储于

    Django 模型中的数据进行编辑;对其它的数据,比如文件系统中的数据,你必须定制视图来编辑。

    就此打住

    现在可以肯定的是,Django 的管理界面 并不 打算成为所有人的万能工具;相反我们选择了专心做一件事情,并把它完成得尽善尽美。

    进行 Django 的管理界面拓展时,必须坚持同样的设计理念。(注意,可扩展性并不是我们的目标)。由于通过定制 Django 视图可以做 任何 事,同时也因为它们可以轻松地通过可视化方式整合到管理界面中(将在下一章将要描述),定制管理界面的内置机会特意地受到一点局限。

    必须记住,尽管管理界面很复杂,但它始终只是一个应用程序。只要有充足的时间,任何 Django的开发者都能做到 admin 接口做到的所有事。 因此,我们需要寄希望于将来会有一个完全不同的 admin 接口会出现,这个新的接口拥有一系列不同的前提假设,并且工作方式也完全不同。

    最后要指出的是,在本文写作之时,Django 开发者们正在进行一个新的管理界面的开发工作,该版本将提供更多定制灵活性。当你阅读本文时,这些新特性也许已经进入了真实的 Django发布之中。你可以向 Django 社区的某些人了解是否已经整合了 newforms-admin 主干代码。

    定制管理模板

    Django 提供了一些用于定制内置 admin 管理模板的工具,我们将简略地介绍一下。而对于其他的任务(比如对于工作流程的控制,或者更细粒度的权限管理),你需要阅读这一章中的 创建自定义的 admin 视图 一节。

    现在,我们来看看如何来快速定制admin 管理接口的外观。第6 章讲到了一些最常见的任务:修改商标(为那些讨厌蓝色的尖发老板),或者提供一个自定义的 form。

    更进一步的目标常常会包含,改变模板中的一些特殊的项。每一种 admin 的视图,包括修改列表、编辑表单、删除确认页以及历史视图,都有一个与之相关联的模板可以以多种方式来进行覆盖。

    首先,你可以在全局上覆盖模板。admin 视图使用标准的模板载入机制来查找模板。所以如果你在模板目录中创建了一个新的模板,Django 会自动地加载它。全局的模板在表 17-1 中列出。

    表 17-1. 全局管理模板

    视图

    基模板名字

    Change list

    admin/change_list.html

    Add/edit form

    admin/change_form.html

    Delete confirmation

    admin/delete_confirmation.html

    Object history

    admin/object_history.html

    大多数时候,你可能只是想修改一个单独的对象或应用程序,而不是修改全局性的设定。因此,每个 admin 视图总是先去查找与模型或应用相关的模板。这些视图寻找模板的顺序如下:

  • admin/<app_label>/<object_name>/<template>.html

  • admin/<app_label>/<template>.html

  • admin/<template>.html

    例如,在 books 这个应用程序中, Book 模块的添加/编辑表单的视图会按如下顺序查找模板:

  • admin/books/book/change_form.html

  • admin/books/change_form.html

  • admin/change_form.html

    自定义模型模板

    大多数时候,你想使用第一个模板来创建特定模型的模板。 通常,最好的办法是扩展基模板和往基模板中定义的区块 中添加信息。

    例如,我们想在那个书籍页面的顶部添加一些帮助文本。 可能是像图 17-1 所示的表单一样的东西。

    image

    图 17-1. 一个自定义管理编辑表单.

    这做起来非常容易:只要建立一个 admin/bookstore/book/change_form.html 模板,并输入下面的代码:

    {% extends "admin/change_form.html" %}

    {% block form_top %}

    <p>Insert meaningful help message here...</p>

    {% endblock %}

    所有这些模板都定义了一些可以被覆盖的块。对于大多数的应用程序来说,代码就是最好的文档,所以我们鼓励你能够详细阅读 admin 的模板来获得最新的信息(它们在 django/contrib/admin/templates/ )。

    自定义 JavaScript

    这些自定义模型模板的常见用途包括,给 admin 页面增加自定义的 javascript 代码来实现一些特殊的视图物件或者是客户端行为。

    幸运的是,这可以更简单。每一个 admin 模板都定义了 {% block extrahead %} ,你可以在

    <head> 元素中加入新的内容。例如你想要增加 jQuery(http://jquery.com/) 到你的 admin历史中,可以这样做:

    {% extends "admin/object_history.html" %}

    {% block extrahead %}

    <script src="http://media.example.com/javascript/jquery.js" type="text/javascript"></script>

    <script type="text/javascript">

    // code to actually use jQuery here...

    </script>

    {% endblock %}备注

    我们并不知道你为什么需要把 jQuery 放入到历史页中,但是这个例子可以被用到任何的模板中。

    你可以使用这种技巧,加入任何的 javascript 代码。

    创建自定义管理视图

    现在,想要往 Django 的 admin 管理接口添加自定义行为的人,可能开始觉得有点奇怪了。我们这里所讲的都是如何改变 admin 管理接口的外观。他们都在喊:如何才能改变 admin 管理接口的内部工作机制。

    首先要提的一点是,这并不神奇。admin 管理接口并没有做任何特殊的事情,它只不过是和其他一些视图一样,简单地处理数据而已。

    确实,这里有相当多的代码; 它必须处理各种各样的操作,字段类型和设置来展示模型的行为. 当你注意到 ADMIN 界面只是一系列视图(Views)的集合,增加自定义的管理视图就变得容易理解了。

    作为举例,让我们为第六章中的图书申请增加一个出版商报告的视图。建立一个 admin 视图用于显示被出版商分好类的书的列表,一个你要建立的自定义 admin 报告试图的极典型的例子。

    首先,在我们的 URLconf 中连接一个视图。插入下面这行: (r'^admin/books/report/$', 'mysite.books.admin_views.report'),在将这行加入这个 admin 视图之前,原本的 URLconf 应该是这样: from django.conf.urls.defaults import *

    urlpatterns = patterns('',

    (r'^admin/bookstore/report/$', 'bookstore.admin_views.report'), (r'^admin/', include('django.contrib.admin.urls')),

    )

    为什么要将定制试图置于管理内容 之前 呢?回想一下,Django 是按照顺序处理 URL 匹配式的。管理内容几乎匹配内容点之后所有的东西,因此如果我们把这几行的顺序颠倒一下,

    Django 将会为该匹配式找到一个内建管理视图,并将试图在 books 应用程序中为 Report模型再入更新列表,而这却是不存在的。

    现在我们开始写视图。为了简单起见,我们只把所有书籍加载到上下文中,让模板用 {% regroup %} 标签来处理分组操作。创建 books/admin_views.py 文件并写入以下内容:

    from mysite.books.models import Book

    from django.template import RequestContext from django.shortcuts import render_to_response

    from django.contrib.admin.views.decorators import staff_member_required

    def report(request):

    return render_to_response( "admin/books/report.html",

    {'book_list' : Book.objects.all()}, RequestContext(request, {}),

    )

    report = staff_member_required(report)

    因为我们但分组操作留给了模板,该视图非常简单。然而,有几段微妙的细节值得我们搞清楚。

    我们使用了 django.contrib.admin.views.decorators 中的 staff_member_required 修饰器。该修饰器与第 12 章中讨论的 login_required 类似,但它还检查所指定的用户是否标记为内部人员,以决定是否允许他访问管理界面。

    该修饰器保护所有内容的管理视图,并使得视图的身份验证逻辑匹配管理界面的其它部分。

    我们在 admin/ 之下解析了一个模板。尽管并非严格要求如此操作,将所有管理模板分组放在 admin 目录中是个好的做法。我们也将应用程序所有的模板放置在名叫 books 的目录中,这也是最佳实践。

    我们将 RequestContext 用作 render_to_response 的第三个参数

    (``context_instance`` )。这就确保了模板可访问当前用户的信息。参看第十章了解更多关于 RequestContext 的信息。

    最后, 我们为这个视图做一个模板。我们将扩展内置管理模板, 以使该视图明确地成为管理界面的一部分.

    {% extends "admin/base_site.html" %}

    {% block title %}List of books by publisher{% endblock %}

    {% block content %}

    <div id="content-main">

    <h1>List of books by publisher:</h1>

    {% regroup book_list|dictsort:"publisher.name" by publisher as books_by_publisher %}

    {% for publisher in books_by_publisher %}

    <h3>{{ publisher.grouper }}</h3>

    <ul>

    {% for book in publisher.list|dictsort:"title" %}

    <li>{{ book }}</li>

    {% endfor %}

    </ul>

    {% endfor %}

    </div>

    {% endblock %}

    通过扩展 admin/base_site.html , 我们没费丝毫气力就得到了 Django 管理界面的外观。图 17-2 我展示了像这样的一个最终结果。

    image

    图 17-2. 一个自定义按出版商归类的图书管理视图

    使用该技术,你可以向管理界面中添加任何你梦想中的东西。需要记住的是这些被叫做定制管理视图实际不过是普通的 Django 视图,你可以使用在本书其它部分所学到的技术制作出符合自己需要的复杂管理界面。

    下面用自定义 admin 视图的一些概念总结一下本章。

    覆盖内置视图

    有时缺省的管理视图无法完成某项工作。你可以轻松地换上自己的定制视图;只需要用自己的 URL 遮蔽内建的管理视图。也就是说,如果在 URLConf 中你的视图出现在缺省管理视图之前,你的视图将取代缺省视图被调用。

    举例来说,我们可以用一个让用户简单输入 ISBN 的窗体来取代内建的书籍创建视图。然后,我们可以从 http://isbn.nu/ 查询该书的信息,并自动地创建对象。

    这样的视图的代码留给读者作为一个练习, 重要的部分是这个 URLconf 代码片断: (r'^admin/bookstore/book/add/$', 'mysite.books.admin_views.add_by_isbn'),

    如果这个代码片段在 URLConf 中出现于管理 URL 之前, add_by_isbn 视图将完全取代标准的管理视图。

    按照这种方式,我们可以替换删除确认页、编辑页面或者管理界面的其它任何部分。

    接下来?

    如果你的母语是英语——我们预料这本英文书的许多读者都是——你可能还没有注意到本书最酷的特性—— 它提供 40 种不同的语言!这大概益于 Django 的国际化架构(以及 Django翻译志愿者的辛勤劳动)。下一章讲解如何使用该架构打造本地化 Django 站点。

    前进!