Skip to main content

编写您的第一个Django应用程序,第7部分

本教程从 教程6 离开时开始。我们将继续使用Web-poll应用程序,并将专注于定制我们在 教程2 中首次探索的Django自动生成的管理站点。

自定义管理表单

通过使用 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

自定义管理更改列表

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

这里是它看起来像这一点:

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 的列标题默认是方法的名称(下划线替换为空格),每行包含输出的字符串表示形式。

你可以通过给这个方法(在 polls/models.py 中)几个属性来改进它,如下所示:

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

有关这些方法属性的更多信息,请参阅 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个项目。 Change list paginationsearch boxesfiltersdate-hierarchiescolumn-header-ordering 都像你认为他们应该一起工作。

自定义管理员外观

显然,在每个管理页面的顶部有“Django管理”是可笑的。它只是占位符文本。

这很容易改变,虽然,使用Django模板系统。 Django管理员由Django本身提供支持,其接口使用Django自己的模板系统。

自定义您的 project’s 模板

在项目目录(包含 manage.py 的目录)中创建一个 templates 目录。模板可以在Django可以访问的文件系统上的任何位置。 (Django作为您的服务器运行的任何用户运行。)然而,保持您的模板在项目中是一个很好的约定。

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

mysite/settings.py
TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(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模板时要检查的文件系统目录的列表;它是一个搜索路径。

组织模板

就像静态文件,我们 could 有我们所有的模板在一起,在一个大的模板目录,它会工作得很好。但是,属于特定应用程序的模板应放置在该应用程序的模板目录(例如 polls/templates)中,而不是项目的(templates)。我们将在 可重用的应用教程 why 中进行更详细的讨论。

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

Django源文件在哪里?

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

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

然后,只需编辑文件,并替换 {{ site_header|default:_('Django administration') }} (包括花括号)与您自己的网站的名称,你认为合适。你应该得到一段代码,如:

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

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

此模板文件包含大量文本,如 {% block branding %}{{ title }}{%{{ 标签是Django模板语言的一部分。当Django渲染 admin/base_site.html 时,这个模板语言将被评估以产生最终的HTML页面,就像我们在 教程3 中看到的。

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

自定义您的 application’s 模板

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

我们的poll应用程序不是很复杂,不需要自定义管理模板。但是,如果它变得更复杂,需要修改Django的标准管理模板的一些功能,修改 application’s 模板将更加明智,而不是 project 中的模板。这样,您可以将投票应用程序包括在任何新项目中,并确保它会找到所需的自定义模板。

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

自定义管理员索引页面

在类似的注释中,您可能想要自定义Django管理索引页面的外观和感觉。

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

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

下一步是什么?

初学者教程在这里结束。在此期间,您可能想要查看 从哪里去 上的一些指针。

如果你熟悉Python包装,并有兴趣学习如何将投票变成一个“可重复使用的应用程序”,请查看 Advanced tutorial: How to write reusable apps