编写你的第一个 Django 应用,第 7 部分

本教程从教程 6结束的地方开始。我们将继续进行网络投票应用程序的开发,并将重点放在自定义 Django 自动生成的管理站点上,我们曾在教程 2中初次探索过。

如何获取帮助

如果您在学习本教程时遇到问题,请前往常见问题解答部分的获取帮助

自定义管理表单

通过使用admin.site.register(Question)注册Question模型,Django 能够构建一个默认的表单表示。通常,您需要自定义管理表单的外观和功能。您可以通过在注册对象时告诉 Django 您想要使用的选项来实现这一点。

让我们看看这是如何通过重新排序编辑表单上的字段来实现的。用以下代码替换admin.site.register(Question)行:

polls/admin.py
from django.contrib import admin

from .models import Question


class QuestionAdmin(admin.ModelAdmin):
    fields = ["pub_date", "question_text"]


admin.site.register(Question, QuestionAdmin)

每当您需要更改模型的管理选项时,都将遵循此模式——创建一个模型管理类,然后将其作为第二个参数传递给admin.site.register()

上述更改使“发布日期”出现在“问题”字段之前。

Fields have been reordered

只有两个字段时,这并不令人印象深刻,但是对于包含数十个字段的管理表单,选择直观的顺序是一个重要的可用性细节。

说到包含数十个字段的表单,您可能希望将表单分成字段集。

polls/admin.py
from django.contrib import admin

from .models import Question


class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None, {"fields": ["question_text"]}),
        ("Date information", {"fields": ["pub_date"]}),
    ]


admin.site.register(Question, QuestionAdmin)

fieldsets中每个元组的第一个元素是字段集的标题。以下是我们表单现在的外观:

Form has fieldsets now

自定义管理更改列表

现在 Question 管理页面看起来不错了,让我们对“更改列表”页面(显示系统中所有问题的页面)进行一些调整。

目前,它的外观如下所示:

Polls change list page

默认情况下,Django 会显示每个对象的str()。但有时如果我们可以显示单个字段,会更有帮助。为此,请使用list_display管理选项,这是一个字段名称列表,将在对象的更改列表页面上作为列显示。

polls/admin.py
class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ["question_text", "pub_date"]

为了确保万无一失,我们还将包含来自教程 2was_published_recently()方法。

polls/admin.py
class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ["question_text", "pub_date", "was_published_recently"]

现在问题更改列表页面如下所示:

Polls change list page, updated

您可以点击列标题按这些值排序——除了was_published_recently标题,因为不支持按任意方法的输出排序。另请注意,was_published_recently的列标题默认情况下是方法的名称(下划线替换为空格),并且每一行都包含输出的字符串表示形式。

您可以通过在该方法上使用display()装饰器(扩展在教程 2中创建的polls/models.py文件)来改进这一点,如下所示:

polls/models.py
from django.contrib import admin


class Question(models.Model):
    # ...
    @admin.display(
        boolean=True,
        ordering="pub_date",
        description="Published recently?",
    )
    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now

有关可通过装饰器配置的属性的更多信息,请参阅list_display

再次编辑您的polls/admin.py文件,并对Question更改列表页面进行改进:使用list_filter进行过滤。将以下行添加到QuestionAdmin中:

list_filter = ["pub_date"]

这将添加一个“筛选器”侧边栏,允许用户按pub_date字段筛选更改列表。

Polls change list page, updated

显示的筛选器类型取决于您正在筛选的字段类型。因为pub_dateDateTimeField,所以 Django 知道要提供合适的筛选器选项:“任何日期”、“今天”、“过去 7 天”、“本月”、“今年”。

这正在逐步完善。让我们添加一些搜索功能。

search_fields = ["question_text"]

这会在更改列表顶部添加一个搜索框。当有人输入搜索词时,Django 将搜索question_text字段。您可以使用任意数量的字段——尽管因为它在幕后使用LIKE查询,所以将搜索字段的数量限制在合理的范围内将使您的数据库更容易进行搜索。

现在也是值得注意的一点是,变更列表提供了免费的分页功能。默认情况下,每页显示 100 个项目。变更列表分页搜索框过滤器日期层次结构列标题排序 都能像你预期的那样协同工作。

自定义管理员外观

显然,在每个管理员页面顶部都显示“Django 管理”是荒谬的。这只是一个占位符文本。

不过,你可以使用 Django 的模板系统来更改它。Django 管理员由 Django 本身驱动,其界面使用 Django 自身的模板系统。

自定义你的项目模板

在你的 djangotutorial 目录中创建一个 templates 目录。模板可以放在 Django 可以访问的文件系统中的任何位置。(Django 以服务器运行的任何用户身份运行。)但是,将你的模板保存在项目中是一个良好的约定。

打开你的设置文件(mysite/settings.py,记住)并在 TEMPLATES 设置中添加 DIRS 选项

mysite/settings.py
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "templates"],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "django.template.context_processors.debug",
                "django.template.context_processors.request",
                "django.contrib.auth.context_processors.auth",
                "django.contrib.messages.context_processors.messages",
            ],
        },
    },
]

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

组织模板

就像静态文件一样,我们可以将所有模板放在一个大型模板目录中,它也能完美地工作。但是,属于特定应用程序的模板应该放在该应用程序的模板目录中(例如 polls/templates),而不是项目的 (templates) 目录中。我们将在可重用应用程序教程中更详细地讨论我们这样做的原因

现在在 templates 内部创建一个名为 admin 的目录,并将模板 admin/base_site.html 从 Django 自身源代码中的默认 Django 管理员模板目录(django/contrib/admin/templates)复制到该目录。

Django 源文件在哪里?

如果你难以找到 Django 源文件在你系统上的位置,请运行以下命令:

$ python -c "import django; print(django.__path__)"
...\> py -c "import django; print(django.__path__)"

然后,编辑该文件并将 {{ site_header|default:_('Django administration') }}(包括花括号)替换为你自己的站点名称。你最终应该得到一段类似这样的代码:

{% block branding %}
<div id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></div>
{% if user.is_anonymous %}
  {% include "admin/color_theme_toggle.html" %}
{% endif %}
{% endblock %}

我们使用这种方法来教你如何覆盖模板。在一个实际项目中,你可能会使用 django.contrib.admin.AdminSite.site_header 属性来更轻松地进行此特定自定义。

此模板文件包含许多类似 {% block branding %}{{ title }} 的文本。{%{{ 标记是 Django 模板语言的一部分。当 Django 渲染 admin/base_site.html 时,此模板语言将被评估以生成最终的 HTML 页面,就像我们在教程 3中看到的那样。

请注意,可以覆盖任何 Django 的默认管理员模板。要覆盖模板,请执行与 base_site.html 相同的操作——将其从默认目录复制到你的自定义目录,然后进行更改。

自定义你的应用程序模板

敏锐的读者会问:但是如果 DIRS 默认情况下为空,Django 是如何找到默认管理员模板的?答案是,由于 APP_DIRS 设置为 True,Django 会自动在每个应用程序包中查找 templates/ 子目录,用作后备(不要忘记 django.contrib.admin 是一个应用程序)。

我们的投票应用程序不是很复杂,不需要自定义管理员模板。但是,如果它变得更复杂,并且需要修改 Django 的标准管理员模板以实现某些功能,那么修改应用程序的模板比修改项目的模板更合理。这样,你就可以将投票应用程序包含在任何新项目中,并确保它可以找到所需的自定义模板。

有关 Django 如何查找其模板的更多信息,请参阅模板加载文档

自定义管理员索引页面

同样,你可能想要自定义 Django 管理员索引页面的外观。

默认情况下,它按字母顺序显示已在管理员应用程序中注册的 INSTALLED_APPS 中的所有应用程序。你可能想要对布局进行重大更改。毕竟,索引页可能是管理员最重要的页面,它应该易于使用。

要自定义的模板是 admin/index.html。(与上一节中的 admin/base_site.html 一样——将其从默认目录复制到你的自定义模板目录)。编辑该文件,你会看到它使用一个名为 app_list 的模板变量。该变量包含每个已安装的 Django 应用程序。你可以不使用它,而是根据你认为最佳的方式硬编码到对象特定管理员页面的链接。

当你熟悉管理员后,请阅读本教程的第 8 部分,了解如何使用第三方软件包。

返回顶部