然后在项目中创建以下目录:
$ mkdir templates/admin/examples/document/ $ mkdir templates/admin/examples/comment/ |
Django admin 的特殊行为将检查目录和应用程序名称(这里是 examples),然后是模型的名称(document 和 comment),然后才能使用系统模版呈现该管理页面。
重写单个模型添加/编辑页面
admin 用来添加和编辑模型实例的页面名称是 change_form.html。首先在 Document 模型目录中创建一个名为 templates/admin/examples/document/change_form.html 的页面,然后将 Django 模版继承线置入其中:{% extends "admin/change_form.html" %}。
现在可以进行定制了。花一些时间熟悉实际的 admin/change_form.html 的内容。它很合理地将一些可以重写的模板块组织到一起,但是有些定制可能需要大量复制模块。不过,使用基于块的模板重写总是比复制整个页面要好。
您想对添加/编辑页面执行哪种定制?对于系统中的每个 Document,您应该展示 5 个最近评论的预览。
首先,创建一些样例内容。
清单 5. 使用 Django shell 创建带几个评论的样例Document
$ python manage.py shell In [1]: from examples import models In [2]: d = models.Document.objects.create(name='Test document', text='This is a test document.') In [3]: for c in range(0, 10): ...: models.Comment.objects.create(text='Comment number %s' % c, document=d) |
现在,admin 列表页面展示一个 Document。选择该 Document 打开默认的添加/编辑页面,如下所示。
图 3. 带有 Document 的默认添加/编辑页面
注意,相关评论不显示。在 admin 中显示相关模型的标准方法是使用强大的 Inline 类。Inline 类允许 admin 用户在单个页面编辑或添加多个相关模型。要查看运行的 inline,按照清单 6 编辑应用程序 admin.py。
清单 6. 向 Document admin 添加相关模型评论
from django.contrib import admin from more_with_admin.examples import models class CommentInline(admin.TabularInline): model = models.Comment class DocumentAdmin(admin.ModelAdmin): inlines = [CommentInline,] class CommentAdmin(admin.ModelAdmin): pass admin.site.register(models.Document, DocumentAdmin) admin.site.register(models.Comment, CommentAdmin) |
图 4 展示了添加 TabularInline 控件之后新的添加/编辑页面。
图 4. 将评论模型作为 Inline 添加之后的添加/编辑页面
这无疑非常强大,但是如果只想快速预览评论的话就没必要这样做了。
这里您可以采取两种方法。一种是使用 Django admin widget 接口编辑与 inline 关联的 HTML widget;Django 文档详细描述了 widget。另一种方法是直接修改添加/编辑页面。如果不希望使用任何特定于 admin 的功能,那么该方法非常有用。
如果不允许编辑评论(可能是由于用户没有足够的权限),但是又想 让用户看到评论,那么可以修改 change_form.html。
Django admin 提供的变量
要在模型实例页面添加功能,您需要了解 admin 已经可以使用什么数据。两个键变量的说明如下。
表 1. 定制 admin 模版需要的变量
变量 | 说明 |
---|---|
object_id | 这是编辑对象时需要的主键。如果要定义特定的实例页面(比如 Document),那么使用该键就够了。 |
content_type_id | 如果要重写多种模型页面,使用该变量查询 ContentTypes 框架来获取模型的名称。更多有关内容类型的信息,请参见 参考资料。 |
为 admin 页面中的内容创建模板标记
列出无法直接输入 Django 模板的相关评论查询代码。最佳的解决方案是使用模板标记。首先,创建模板标记目录 and __init__.py 文件:
$ mkdir examples/templatetags/ $ touch examples/templatetags/__init__.py |
创建一个名为 examples/templatetags/example_tags.py 的新文件,并添加以下代码。
清单 7. 根据给定 Document ID 检索评论的模板标签
from django import template from examples import models register = template.Library() @register.inclusion_tag('comments.html') def display_comments(document_id): document = models.Document.objects.get(id__exact=document_id) comments = models.Comment.objects.filter(document=document)[0:5] return { 'comments': comments } |
由于这是一个包含标签,您需要创建相应的模板文件:comments.html。编辑 examples/templates/comments.html 文件并输入清单 8 中的代码。
清单 8. 显示评论预览集的模板
{% for comment in comments %} <blockquote>{{ comment.text }}</blockquote> {% endfor %} |
现在可以将它添加到 admin 页面了。在 admin.py 中注释掉对 CommentInline 的引用,并按照清单 9 更改 change_form.html 的本地版本。
清单 9. 在添加/编辑页面包含模板标签
{% extends "admin/change_form.html" %} {% load example_tags %} {% block after_field_sets %} {% if object_id %}{% display_comments object_id %}{% endif %} {% endblock %} |
在使用前检查 object_id 的存在很重要,因为 change_form.html 还可以用来创建新实例,在这种情况下 object_id 不可用。after_field_sets 块只是 admin 中提供的众多扩展点之一。其他请参考 change_form.html 源页面。
图 5 展示了更新后的表格。
图 5. 包含模板标记之后的添加/编辑页面
修改 admin 行为
模板重写只能做这么多了。如果您想更改 admin 的实际流和行为怎么办呢?修改源代码不是不可能,但是那会让您受制于更新时使用的特定 Django 版本。
重写 AdminModel 方法
默认情况下,在 admin 中单击 Save 将用户带回到列表页面。通常这没有问题,但是如果您想直接到 admin 外部的对象预览页面,那应该怎么办?在开发内容管理系统 (CMS) 时这种情况很常见。
|
admin 应用程序中的大部分功能都附加到 admin.ModelAdmin 类。这是该对象从 admin.py 中继承的类。您可以重写许多许多公开方法。类定义请查看 admin-source/options.py 中的源代码。
有两种方法可以更改 Save 按钮的行为:您可以重写 admin.ModelAdmin.response_add,该按钮负责保存后的实际重定向;还可以重写 admin.ModelAdmin.change_view。后一种方式更为简单。
清单 10. 保存事件之后重写指向用户的页面
class DocumentAdmin(admin.ModelAdmin): def change_view(self, request, object_id, extra_context=None): result = super(DocumentAdmin, self).change_view(request, object_id, extra_context) document = models.Document.objects.get(id__exact=object_id) if not request.POST.has_key('_addanother') and not request.POST.has_key('_continue'): result['Location'] = document.get_absolute_url() return result |