Django 教程 第 4 部分:Django 管理站点

现在,我们已经为LocalLibrary网站创建了模型,我们将使用Django Admin站点添加一些“真实”的书籍数据。首先,我们将向您展示如何将模型注册到admin站点,然后我们将向您展示如何登录并创建一些数据。在文章的最后,我们将展示一些可以进一步改进Admin站点展示的方法。

先决条件 首先完成:Django教程第3部分:使用模型
目标 了解Django admin站点的优点和局限性,并使用它为我们的模型创建一些记录。

概述

Django admin应用程序可以使用您的模型自动构建一个站点区域,您可以使用它来创建、查看、更新和删除记录。这可以在开发过程中为您节省大量时间,使您能够轻松地测试您的模型,并了解您是否拥有正确的数据。admin应用程序还可以用于管理生产环境中的数据,具体取决于网站类型。Django项目建议将其仅用于内部数据管理(即仅供管理员或您组织内部人员使用),因为以模型为中心的做法并不一定是所有用户的最佳界面,并且会公开大量关于模型的不必要细节。

将admin应用程序包含到您的网站中所需的所有配置是在您创建骨架项目时自动完成的(有关所需实际依赖项的信息,请参阅此处的Django文档)。因此,您必须做的就是将您的模型注册到admin应用程序。在本文的最后,我们将简要演示如何进一步配置admin区域以更好地显示我们的模型数据。

注册模型后,我们将展示如何创建一个新的“超级用户”,登录站点并创建一些书籍、作者、书籍实例和流派。这些对于我们在下一个教程中开始创建的视图和模板进行测试将很有用。

注册模型

首先,打开目录应用程序中的admin.py/django-locallibrary-tutorial/catalog/admin.py)。它目前看起来像这样——请注意它已经导入了django.contrib.admin

python
from django.contrib import admin

# Register your models here.

通过将以下文本复制到文件底部来注册模型。此代码导入模型,然后调用admin.site.register来注册每个模型。

python
from .models import Author, Genre, Book, BookInstance, Language

admin.site.register(Book)
admin.site.register(Author)
admin.site.register(Genre)
admin.site.register(BookInstance)
admin.site.register(Language)

注意:上面的行假设您接受了创建模型来表示书籍的自然语言的挑战(请参阅模型教程文章)!

这是将模型或多个模型注册到站点最简单的方法。admin站点高度可定制,我们将在后面详细讨论其他注册模型的方法。

创建超级用户

为了登录admin站点,我们需要一个启用了Staff状态的用户帐户。为了查看和创建记录,我们还需要这个用户具有管理所有对象的权限。您可以使用manage.py创建一个具有对站点和所有所需权限的完全访问权限的“超级用户”帐户。

在与manage.py相同的目录中调用以下命令以创建超级用户。系统将提示您输入用户名、电子邮件地址和密码。

bash
python3 manage.py createsuperuser

完成此命令后,将向数据库添加一个新的超级用户。现在重新启动开发服务器,以便我们可以测试登录

bash
python3 manage.py runserver

登录并使用该站点

要登录到站点,请打开/admin URL(例如http://127.0.0.1:8000/admin)并输入您的新超级用户用户 ID 和密码凭据(您将被重定向到登录页面,然后在输入详细信息后返回到/admin URL)。

站点的这部分显示了我们所有的模型,按已安装的应用程序分组。您可以单击模型名称转到一个显示其所有关联记录的屏幕,并且您还可以进一步单击这些记录以编辑它们。您也可以直接单击每个模型旁边的添加链接以开始创建该类型的记录。

Admin Site - Home page

单击书籍右侧的添加链接以创建一本新书(这将显示一个类似于下面的对话框)。请注意,每个字段的标题、使用的窗口小部件类型和help_text(如果有)与您在模型中指定的数值相匹配。

为字段输入值。您可以通过按相应字段旁边的+按钮来创建新的作者或流派(或者如果您已经创建了它们,则从列表中选择现有值)。完成后,您可以按保存保存并添加另一个保存并继续编辑来保存记录。

Admin Site - Book Add

注意:在这一点上,我们希望您花一些时间向您的应用程序添加一些书籍、作者、语言和流派(例如奇幻)。确保每个作者和流派都包含几本不同的书籍(这将使您在以后的文章系列中实现列表和详细信息视图时更加有趣)。

添加完书籍后,单击顶部书签中的主页链接返回到admin页面。然后单击书籍链接以显示当前的书籍列表(或单击其他链接以查看其他模型列表)。现在,您已经添加了一些书籍,该列表可能类似于下面的屏幕截图。每本书的标题都显示出来;这是在上一篇文章中指定的__str__()方法在Book模型中返回的值。

Admin Site - List of book objects

从这个列表中,您可以通过选中不想保留的书籍旁边的复选框,从操作下拉列表中选择删除…操作,然后按执行按钮来删除书籍。您还可以通过按添加书籍按钮来添加新书籍。

您可以通过选择链接中的书名来编辑书籍。书籍的编辑页面(如下所示)与“添加”页面几乎相同。主要区别在于页面标题(更改书籍)以及删除历史记录在站点上查看按钮的添加(最后一个按钮出现是因为我们在模型中定义了get_absolute_url()方法)。

注意:单击在站点上查看按钮会引发NoReverseMatch异常,因为get_absolute_url()方法尝试反转()一个尚未定义的命名 URL 映射('book-detail')。我们将在Django教程第6部分:通用列表和详细信息视图中定义 URL 映射和关联视图。

Admin Site - Book Edit

现在导航回主页(使用面包屑轨迹中的主页链接),然后查看作者流派列表——您应该已经从添加新书籍时创建了许多,但您可以随意添加更多。

您没有的是任何书籍实例,因为它们不是从书籍创建的(尽管您可以从BookInstance创建Book——这是ForeignKey字段的性质)。导航回主页,然后按关联的添加按钮以显示下面的添加书籍实例屏幕。请注意大型的、全局唯一的 ID,该 ID 可用于单独识别图书馆中的一本特定书籍。

Admin Site - BookInstance Add

为您的每本书创建多个此类记录。将至少一些记录的状态设置为可用,将其他记录的状态设置为借出。如果状态不是可用,则还应设置将来的到期日期

就是这样!您现在已经了解了如何设置和使用管理站点。您还为BookBookInstanceGenreLanguageAuthor创建了记录,我们将在创建自己的视图和模板时使用这些记录。

高级配置

Django 在使用注册模型中的信息创建基本管理站点方面做得很好

  • 每个模型都有一个单独的记录列表,由使用模型的__str__()方法创建的字符串标识,并链接到用于编辑的详细信息视图/表单。默认情况下,此视图在顶部有一个操作菜单,您可以使用它对记录执行批量删除操作。
  • 用于编辑和添加记录的模型详细信息记录表单包含模型中的所有字段,按声明顺序垂直排列。

您可以进一步定制界面,使其更易于使用。您可以做的一些事情包括

  • 列表视图
    • 为每个记录添加要显示的附加字段/信息。
    • 添加过滤器以根据日期或其他选择值(例如书籍借阅状态)选择要列出的记录。
    • 在列表视图中的操作菜单中添加更多选项,并选择此菜单在表单上的显示位置。
  • 详细信息视图
    • 选择要显示(或排除)的字段,以及它们的顺序、分组、是否可编辑、使用的窗口小部件、方向等。
    • 向记录添加相关字段,以允许内联编辑(例如,在创建作者记录时添加并编辑书籍记录的能力)。

在本节中,我们将查看一些更改,这些更改将改进我们的LocalLibrary的界面,包括向BookAuthor模型列表添加更多信息,并改进其编辑视图的布局。我们不会更改LanguageGenre模型的演示,因为它们每个只有一个字段,因此这样做没有实际好处!

您可以在Django Admin站点(Django 文档)中找到所有管理站点定制选择的完整参考。

注册 ModelAdmin 类

要更改模型在管理界面中的显示方式,请定义一个ModelAdmin类(它描述了布局),并将其注册到模型。

让我们从Author模型开始。打开目录应用程序中的admin.py/django-locallibrary-tutorial/catalog/admin.py)。将您最初的Author模型注册注释掉(在其前面加上一个 #)。

python
# admin.site.register(Author)

现在添加一个新的AuthorAdmin和注册,如下所示。

python
# Define the admin class
class AuthorAdmin(admin.ModelAdmin):
    pass

# Register the admin class with the associated model
admin.site.register(Author, AuthorAdmin)

现在,我们将为BookBookInstance添加ModelAdmin类。我们再次需要注释掉原始注册

python
# admin.site.register(Book)
# admin.site.register(BookInstance)

现在创建并注册新模型;为了进行演示,我们将改用@register装饰器来注册模型(这与admin.site.register()语法完全相同)

python
# Register the Admin classes for Book using the decorator
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    pass

# Register the Admin classes for BookInstance using the decorator
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
    pass

目前,我们所有的管理类都是空的(请参阅pass),因此管理行为将保持不变!我们现在可以扩展它们以定义我们特定于模型的管理行为。

配置列表视图

LocalLibrary目前使用从模型__str__()方法生成的物体名称来列出所有作者。当您只有几个作者时,这很好,但是当您有很多作者时,您最终可能会出现重复项。为了区分它们,或者仅仅是因为您想显示有关每个作者的更多有趣信息,您可以使用list_display在视图中添加更多字段。

将您的AuthorAdmin类替换为下面的代码。要在列表中显示的字段名称在所需的顺序中以元组形式声明,如所示(这些名称与您最初的模型中指定的名称相同)。

python
class AuthorAdmin(admin.ModelAdmin):
    list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')

现在导航到您网站中的作者列表。上面的字段现在应该显示,如下所示

Admin Site - Improved Author List

对于我们的Book 模型,我们将额外显示authorgenreauthor 是一个ForeignKey 字段(一对多)关系,因此将由关联记录的__str__() 值表示。将BookAdmin 类替换为以下版本。

python
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'display_genre')

不幸的是,我们不能直接在list_display 中指定genre 字段,因为它是一个ManyToManyField(Django 阻止了这种情况,因为这样做会产生很大的数据库访问“成本”)。相反,我们将定义一个display_genre 函数来获取信息作为字符串(这是我们在上面调用的函数;我们将在下面定义它)。

注意: 获取genre 这里可能不是一个好主意,因为数据库操作的“成本”。我们向您展示如何做,因为在模型中调用函数在其他情况下非常有用——例如,在列表中的每个项目旁边添加一个删除链接。

将以下代码添加到您的Book 模型(models.py)中。这将从genre 字段的前三个值(如果存在)创建一个字符串,并创建一个可以在管理站点中用于此方法的short_description

python
def display_genre(self):
    """Create a string for the Genre. This is required to display genre in Admin."""
    return ', '.join(genre.name for genre in self.genre.all()[:3])

display_genre.short_description = 'Genre'

保存模型和更新的管理界面后,打开您的网站并转到书籍列表页面;您应该会看到如下所示的书籍列表

Admin Site - Improved Book List

Genre 模型(以及Language 模型,如果您定义了一个)都只有一个字段,因此没有必要为它们创建额外的模型来显示其他字段。

注意: 值得更新BookInstance 模型列表,以至少显示状态和预期的归还日期。我们在本文末尾添加了一个挑战作为挑战!

添加列表过滤器

当列表中有很多项目时,能够过滤显示哪些项目会很有用。这可以通过在list_filter 属性中列出字段来完成。将您当前的BookInstanceAdmin 类替换为以下代码片段。

python
class BookInstanceAdmin(admin.ModelAdmin):
    list_filter = ('status', 'due_back')

列表视图现在将在右侧包含一个过滤器框。注意您如何选择日期和状态来过滤值

Admin Site - BookInstance List Filters

组织详细信息视图布局

默认情况下,详细信息视图将所有字段垂直排列,按照它们在模型中的声明顺序排列。您可以更改声明顺序,哪些字段显示(或排除),是否使用部分来组织信息,字段是水平显示还是垂直显示,甚至在管理表单中使用什么编辑小部件。

注意:LocalLibrary 模型相对简单,因此我们不需要大量更改布局;然而,我们还是会做一些更改,只是为了向您展示如何做。

控制显示和排列哪些字段

更新您的AuthorAdmin 类以添加fields 行,如下所示

python
class AuthorAdmin(admin.ModelAdmin):
    list_display = ('last_name', 'first_name', 'date_of_birth', 'date_of_death')

    fields = ['first_name', 'last_name', ('date_of_birth', 'date_of_death')]

fields 属性仅列出了要在表单中显示的字段,按顺序排列。默认情况下,字段会垂直显示,但如果将它们进一步分组在一个元组中(如上面的“日期”字段所示),则会水平显示。

在您的网站上,转到作者详细信息视图——它现在应该显示如下

Admin Site - Improved Author Detail

注意:您还可以使用exclude 属性来声明要从表单中排除的属性列表(模型中的所有其他属性都将显示)。

对详细信息视图进行分区

您可以使用fieldsets 属性,在详细信息表单内添加“部分”来对相关的模型信息进行分组。

BookInstance 模型中,我们有与书籍本身相关的信息(即nameimprintid),以及它何时可用(statusdue_back)。我们可以使用fieldsets 属性,将这些添加到我们的BookInstanceAdmin 类中,如下所示。

python
@admin.register(BookInstance)
class BookInstanceAdmin(admin.ModelAdmin):
    list_filter = ('status', 'due_back')

    fieldsets = (
        (None, {
            'fields': ('book', 'imprint', 'id')
        }),
        ('Availability', {
            'fields': ('status', 'due_back')
        }),
    )

每个部分都有自己的标题(或None,如果您不想要标题)以及一个与之关联的字段元组字典——格式难以描述,但如果您查看上面的代码片段,则很容易理解。

现在导航到您的网站中的书籍实例视图;表单应该显示如下

Admin Site - Improved BookInstance Detail with sections

关联记录的内联编辑

有时,能够同时添加关联记录是有意义的。例如,在同一个详细信息页面上同时拥有书籍信息和您所拥有特定副本的信息可能是有意义的。

您可以通过声明inlines 来实现这一点,该内联的类型为TabularInline(水平布局)或StackedInline(垂直布局,与默认模型布局相同)。您可以通过在您的BookAdmin 中指定inlines,将BookInstance 信息内联添加到我们的Book 详细信息中

python
class BooksInstanceInline(admin.TabularInline):
    model = BookInstance

@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
    list_display = ('title', 'author', 'display_genre')

    inlines = [BooksInstanceInline]

现在导航到您的网站中Book 的视图——在底部,您现在应该看到与该书籍相关的书籍实例(紧接在书籍的类型字段下方)

Admin Site - Book with Inlines

在这种情况下,我们所做的只是声明了我们的表格内联类,它只是添加了来自内联模型的所有字段。您可以为布局指定各种其他信息,包括要显示的字段、它们的顺序、它们是否为只读等等(有关更多信息,请参阅TabularInline)。

注意:此功能有一些令人痛苦的限制!在上图中,我们有三个现有的书籍实例,后面是三个新的书籍实例的占位符(它们看起来非常相似!)。最好默认情况下没有多余的书籍实例,只需使用添加另一个书籍实例链接添加它们,或者能够从这里以不可读链接的形式列出BookInstance。第一个选项可以通过在BooksInstanceInline 模型中将extra 属性设置为0 来完成,您可以自己尝试。

挑战自己

在本节中,我们学到了很多东西,所以现在是您尝试一些东西的时候了。

  1. 对于BookInstance 列表视图,添加代码以显示书籍、状态、应还日期和 ID(而不是默认的__str__() 文本)。
  2. 使用与我们为Book/BookInstance 所做的相同方法,将Book 项目的内联列表添加到Author 详细信息视图中。

总结

就是这样!您现在已经学会了如何在最简单和改进的形式下设置管理站点,如何创建超级用户,以及如何导航管理站点并查看、删除和更新记录。在此过程中,您创建了一堆书籍、书籍实例、类型和作者,我们将在创建自己的视图和模板后能够列出和显示它们。

进一步阅读