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

本教程从Tutorial 6停止的地方开始。 我们继续使用Web轮询应用程序,并将重点定制我们首先在Tutorial 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() - 任何时候需要更改模型的管理选项。

上面的这个特殊变化使得“Date published”在“Question Text”之前:

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中每个元组的第一个元素是fieldset的标题。 以下是我们的表单现在的样子:

Form has fieldsets now

自定义管理员更改列表

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

这里是这个样子:

Polls change list page

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

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

为了更好的衡量,我们还要包含来自Tutorial 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文件,并使用list_filterQuestion更改列表页面添加改进。 将以下行添加到QuestionAdmin中:

list_filter = ['pub_date']

这增加了一个“过滤器”边栏,让人们可以通过pub_date字段过滤更改列表:

Polls change list page, updated

显示的过滤器类型取决于您要过滤的字段的类型。 因为pub_date是一个DateTimeField,Django知道给出适当的过滤选项:“任何日期”,“今天”,“过去7天”,“本月”,“年”。

这个塑造得很好。 让我们添加一些搜索功能:

search_fields = ['question_text']

在更改列表的顶部添加了一个搜索框。 当有人输入搜索条件时,Django将搜索question_text字段。 你可以使用尽可能多的字段 - 尽管因为它在后台使用了一个LIKE查询,所以将搜索字段的数量限制在一个合理的数字将使数据库更容易执行搜索。

现在也是一个很好的时间来注意,变更列表给你免费的分页。 默认是每页显示100个项目。 Change list pagination, search boxes, filters, date-hierarchies, and column-header-ordering all work together like you think they should.

自定义管理员的外观和感觉

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

不过,使用Django的模板系统很容易改变。 Django管理员是由Django本身支持的,其接口使用Django自己的模板系统。

自定义您的项目的模板

在您的项目目录(包含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 is a list of filesystem directories to check when loading Django templates; it’s a search path.

组织模板

Just like the static files, we could have all our templates together, in one big templates directory, and it would work perfectly well. 但是,属于特定应用程序的模板应该放置在该应用程序的模板目录中(例如polls/templates),而不是项目的templates 我们将在reusable apps tutorial 为什么我们这样做。

Now create a directory called admin inside templates, and copy the template admin/base_site.html from within the default Django admin template directory in the source code of Django itself (django/contrib/admin/templates) into that directory.

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属性来更轻松地进行此特定定制。

This template file contains lots of text like {% block branding %} and {{ title }}. {%{{标签是Django模板语言的一部分。 当Django呈现admin/base_site.html时,将会评估此模板语言以生成最终的HTML页面,就像我们在Tutorial 3中看到的那样。

请注意,任何Django的默认管理模板都可以被覆盖。 To override a template, just do the same thing you did with base_site.html – copy it from the default directory into your custom directory, and make changes.

定制您的应用程序的模板

Astute readers will ask: But if DIRS was empty by default, how was Django finding the default admin templates? The answer is that, since APP_DIRS is set to True, Django automatically looks for a templates/ subdirectory within each application package, for use as a fallback (don’t forget that django.contrib.admin is an application).

我们的投票应用程序不是很复杂,不需要自定义管理模板。 但是,如果它变得更加复杂,并且需要修改Django标准管理模板的某些功能,那么修改应用程序的模板,而不是项目 t1 >。 这样,你可以在任何新项目中包含民意调查应用程序,并确保它会找到它需要的自定义模板。

有关Django如何找到其模板的更多信息,请参阅template loading documentation

自定义管理索引页面

在类似的说明中,您可能想要自定义Django管理索引页面的外观。

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

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

接下来是什么?

初学者教程在这里结束。 与此同时,您可能需要查看一下where to go from here

如果您熟悉Python打包,并且有兴趣学习如何将民意调查变成“可重复使用的应用程序”,请查看Advanced tutorial: How to write reusable apps