Django 管理站点¶
Django 最强大的部分之一是自动管理界面。它从模型中读取元数据,以提供一个快速、以模型为中心界面,受信任的用户可以在其中管理网站上的内容。建议将管理界面用作组织的内部管理工具。它不适用于构建整个前端。
管理界面有许多用于自定义的钩子,但请注意不要尝试专门使用这些钩子。如果你需要提供一个更以流程为中心的界面,该界面抽象了数据库表和字段的实现细节,那么可能需要编写自己的视图。
在本文档中,我们将讨论如何激活、使用和自定义 Django 的管理界面。
概览¶
管理界面在 startproject
使用的默认项目模板中启用。
如果你不使用默认项目模板,则以下为要求
- 添加
'django.contrib.admin'
及其依赖项 -django.contrib.auth
、django.contrib.contenttypes
、django.contrib.messages
和django.contrib.sessions
- 到INSTALLED_APPS
设置。 - 在
TEMPLATES
设置中配置DjangoTemplates
后端,并在OPTIONS
的'context_processors'
选项中使用django.template.context_processors.request
、django.contrib.auth.context_processors.auth
和django.contrib.messages.context_processors.messages
。 - 如果您自定义了
MIDDLEWARE
设置,则必须包含django.contrib.auth.middleware.AuthenticationMiddleware
和django.contrib.messages.middleware.MessageMiddleware
。 - 将管理的 URL 连接到您的 URLconf.
完成这些步骤后,您将可以通过访问您连接到的 URL(默认情况下为 /admin/
)来使用管理站点。
如果您需要创建一个用户来登录,请使用 createsuperuser
命令。默认情况下,登录到管理需要用户将 is_staff
属性设置为 True
。
最后,确定应用程序的哪些模型应该在管理界面中可编辑。对于这些模型中的每一个,请按照 ModelAdmin
中所述将其注册到管理。
其他主题¶
ModelAdmin
对象¶
-
class
ModelAdmin
¶ ModelAdmin
类是管理员界面中模型的表示形式。通常,这些内容存储在应用程序中名为admin.py
的文件中。我们来看看ModelAdmin
的一个示例from django.contrib import admin from myapp.models import Author class AuthorAdmin(admin.ModelAdmin): pass admin.site.register(Author, AuthorAdmin)
您需要
ModelAdmin
对象吗?在前面的示例中,
ModelAdmin
类未定义任何自定义值(尚未定义)。因此,将提供默认管理员界面。如果您对默认管理员界面感到满意,则根本不需要定义ModelAdmin
对象 - 您可以注册模型类而不提供ModelAdmin
描述。前面的示例可以简化为from django.contrib import admin from myapp.models import Author admin.site.register(Author)
register
装饰器¶
-
register
(*models, site=django.contrib.admin.sites.site)¶ 还有一个装饰器用于注册您的
ModelAdmin
类from django.contrib import admin from .models import Author @admin.register(Author) class AuthorAdmin(admin.ModelAdmin): pass
它给出了一个或多个模型类来使用
ModelAdmin
注册。如果您正在使用自定义AdminSite
,请使用site
关键字参数传递from django.contrib import admin from .models import Author, Editor, Reader from myproject.admin_site import custom_admin_site @admin.register(Author, Reader, Editor, site=custom_admin_site) class PersonAdmin(admin.ModelAdmin): pass
如果您必须在
__init__()
方法中引用您的模型管理员类,则不能使用此装饰器,例如super(PersonAdmin, self).__init__(*args, **kwargs)
。您可以使用super().__init__(*args, **kwargs)
。
发现管理文件¶
当你在 INSTALLED_APPS
设置中放入 'django.contrib.admin'
时,Django 会自动在每个应用程序中查找 admin
模块并导入它。
-
class
apps.
AdminConfig
¶ 这是用于管理的默认
AppConfig
类。它在 Django 启动时调用autodiscover()
。
-
class
apps.
SimpleAdminConfig
¶ 此类与
AdminConfig
类似,但它不会调用autodiscover()
。
-
autodiscover
()¶ 此函数尝试在每个已安装的应用程序中导入
admin
模块。此类模块应向管理员注册模型。通常,您无需直接调用此函数,因为
AdminConfig
在 Django 启动时会调用此函数。
如果您使用自定义 AdminSite
,则通常将所有 ModelAdmin
子类导入到您的代码中,并将其注册到自定义 AdminSite
中。在这种情况下,为了禁用自动发现,您应在 INSTALLED_APPS
设置中将 'django.contrib.admin.apps.SimpleAdminConfig'
替换为 'django.contrib.admin'
。
ModelAdmin
选项¶
ModelAdmin
非常灵活。它有几个选项用于处理界面的自定义。所有选项均在 ModelAdmin
子类上定义
from django.contrib import admin
class AuthorAdmin(admin.ModelAdmin):
date_hierarchy = "pub_date"
-
ModelAdmin.
actions_on_top
¶
-
ModelAdmin.
actions_on_bottom
¶ 控制操作栏在页面上的显示位置。默认情况下,管理更改列表在页面顶部显示操作(
actions_on_top = True; actions_on_bottom = False
)。
-
ModelAdmin.
actions_selection_counter
¶ 控制是否在操作下拉菜单旁边显示一个选择计数器。默认情况下,管理员变更列表会显示它 (
actions_selection_counter = True
)。
-
ModelAdmin.
date_hierarchy
¶ 将
date_hierarchy
设置为模型中DateField
或DateTimeField
的名称,变更列表页面将包含按该字段进行基于日期的向下钻取导航。示例
date_hierarchy = "pub_date"
您还可以使用
__
查找指定相关模型上的字段,例如date_hierarchy = "author__pub_date"
它将根据可用数据智能地填充自身,例如,如果所有日期都在一个月内,它将仅显示按天钻取。
注意
date_hierarchy
在内部使用QuerySet.datetimes()
。当启用时区支持时,请参阅其文档以了解一些注意事项 (USE_TZ = True
)。
-
ModelAdmin.
empty_value_display
¶ 此属性会覆盖记录中为空(
None
、空字符串等)的字段的默认显示值。默认值为-
(破折号)。例如from django.contrib import admin class AuthorAdmin(admin.ModelAdmin): empty_value_display = "-empty-"
您还可以使用
AdminSite.empty_value_display
覆盖所有管理页面的empty_value_display
,或针对特定字段执行此操作from django.contrib import admin class AuthorAdmin(admin.ModelAdmin): list_display = ["name", "title", "view_birth_date"] @admin.display(empty_value="???") def view_birth_date(self, obj): return obj.birth_date
-
ModelAdmin.
exclude
¶ 如果给定了此属性,它应为要从表单中排除的字段名称列表。
例如,让我们考虑以下模型
from django.db import models class Author(models.Model): name = models.CharField(max_length=100) title = models.CharField(max_length=3) birth_date = models.DateField(blank=True, null=True)
如果您想要一个仅包含
name
和title
字段的Author
模型表单,则可以像这样指定fields
或exclude
from django.contrib import admin class AuthorAdmin(admin.ModelAdmin): fields = ["name", "title"] class AuthorAdmin(admin.ModelAdmin): exclude = ["birth_date"]
由于 Author 模型只有三个字段,即
name
、title
和birth_date
,因此由上述声明生成的表单将包含完全相同的字段。
-
ModelAdmin.
fields
¶ 使用
fields
选项可在“添加”和“更改”页面上的表单中进行简单的布局更改,例如仅显示可用字段的子集、修改其顺序或将它们分组到行中。例如,您可以为django.contrib.flatpages.models.FlatPage
模型定义一个更简单的管理表单版本,如下所示class FlatPageAdmin(admin.ModelAdmin): fields = ["url", "title", "content"]
在上述示例中,只有字段
url
、title
和content
将按顺序显示在表单中。fields
可以包含在ModelAdmin.readonly_fields
中定义的值,以只读方式显示。对于更复杂的布局需求,请参见
fieldsets
选项。fields
选项接受与list_display
相同类型的的值,但它不接受可调用对象。模型和模型管理方法的名称仅在它们列在readonly_fields
中时才会使用。要在同一行显示多个字段,请将这些字段包装在它们自己的元组中。在此示例中,
url
和title
字段将显示在同一行,而content
字段将显示在其下方自己的行上class FlatPageAdmin(admin.ModelAdmin): fields = [("url", "title"), "content"]
可能与
ModelAdmin.fieldsets
选项混淆此
fields
选项不应与fieldsets
选项中的fields
字典键混淆,如下一节所述。如果
fields
和fieldsets
选项均不存在,Django 将默认显示每个非AutoField
且editable=True
的字段,在单个字段集中,按照模型中字段定义的顺序显示。
-
ModelAdmin.
fieldsets
¶ 设置
fieldsets
以控制管理“添加”和“更改”页面的布局。fieldsets
是一个 2 元组列表,其中每个 2 元组表示管理表单页面上的一个<fieldset>
。(<fieldset>
是表单的一个“部分”。)2 元组的格式为
(name, field_options)
,其中name
是表示字段集标题的字符串,field_options
是有关字段集的信息字典,包括要在其中显示的字段列表。一个完整的示例,取自
django.contrib.flatpages.models.FlatPage
模型from django.contrib import admin class FlatPageAdmin(admin.ModelAdmin): fieldsets = [ ( None, { "fields": ["url", "title", "content", "sites"], }, ), ( "Advanced options", { "classes": ["collapse"], "fields": ["registration_required", "template_name"], }, ), ]
这将生成一个类似于以下内容的管理页面
如果
fieldsets
和fields
选项均不存在,Django 将默认显示每个非AutoField
且editable=True
的字段,在单个字段集中,按照模型中字段定义的顺序显示。field_options
字典可以有以下键fields
要在该字段集中显示的字段名称列表或元组。此键是必需的。
示例
{ "fields": ["first_name", "last_name", "address", "city", "state"], }
与
fields
选项一样,若要在同一行显示多个字段,请将这些字段包装在它们自己的元组中。在此示例中,first_name
和last_name
字段将显示在同一行{ "fields": [("first_name", "last_name"), "address", "city", "state"], }
fields
可以包含readonly_fields
中定义的值,以只读方式显示。如果你将可调用对象的名称添加到
fields
,则与fields
选项一样,适用相同的规则:可调用对象必须列在readonly_fields
中。
classes
包含要应用于字段集的额外 CSS 类的列表或元组。
示例
{ "classes": ["wide", "extrapretty"], }
默认管理站点样式表定义的两个有用的类是
collapse
和wide
。具有collapse
样式的字段集最初将在管理中折叠,并替换为一个小的“点击展开”链接。具有wide
样式的字段集将获得额外的水平空间。
description
一个可选的额外文本字符串,显示在每个字段集的顶部,在字段集的标题下方。由于其布局,此字符串不会为
TabularInline
呈现。请注意,当在管理界面中显示此值时,此值不会转义 HTML。如果您愿意,这将允许您包含 HTML。或者,您可以使用纯文本和
django.utils.html.escape()
来转义任何 HTML 特殊字符。
-
ModelAdmin.
filter_horizontal
¶ 默认情况下,
ManyToManyField
在管理站点中显示为<select multiple>
。但是,在选择许多项目时,使用多选框可能很困难。将ManyToManyField
添加到此列表中,将改为使用一个巧妙的不显眼的 JavaScript “筛选器”界面,该界面允许在选项中进行搜索。未选中的选项和选中的选项并排出现在两个框中。请参阅filter_vertical
以使用垂直界面。
-
ModelAdmin.
filter_vertical
¶ 与
filter_horizontal
相同,但使用筛选器界面的垂直显示,其中未选定选项的框显示在选定选项的框上方。
-
ModelAdmin.
form
¶ 默认情况下,会为您的模型动态创建一个
ModelForm
。它用于创建添加/更改页面上显示的表单。您可轻松提供自己的ModelForm
以覆盖添加/更改页面上的任何默认表单行为。或者,您可以使用ModelAdmin.get_form()
方法自定义默认表单,而不是指定一个全新的表单。有关示例,请参阅部分 向管理中添加自定义验证。
ModelAdmin.exclude
优先如果您的
ModelForm
和ModelAdmin
都定义了exclude
选项,那么ModelAdmin
优先from django import forms from django.contrib import admin from myapp.models import Person class PersonForm(forms.ModelForm): class Meta: model = Person exclude = ["name"] class PersonAdmin(admin.ModelAdmin): exclude = ["age"] form = PersonForm
在上面的示例中,“age”字段将被排除,但“name”字段将包含在生成的表单中。
-
ModelAdmin.
formfield_overrides
¶ 这提供了一种快速且简单的方法来覆盖一些
Field
选项以在管理中使用。formfield_overrides
是一个字典,将字段类映射到在构造时传递给字段的参数字典。由于这有点抽象,我们来看一个具体的示例。
formfield_overrides
最常见的用法是为特定类型的字段添加自定义小部件。因此,假设我们编写了一个RichTextEditorWidget
,我们希望将其用于大型文本字段,而不是默认的<textarea>
。以下是如何做到这一点from django.contrib import admin from django.db import models # Import our custom widget and our model from where they're defined from myapp.models import MyModel from myapp.widgets import RichTextEditorWidget class MyModelAdmin(admin.ModelAdmin): formfield_overrides = { models.TextField: {"widget": RichTextEditorWidget}, }
请注意,字典中的键是实际的字段类,而不是字符串。该值是另一个字典;这些参数将传递给表单字段的
__init__()
方法。有关详细信息,请参阅 表单 API。警告
如果您想对关系字段(即
ForeignKey
或ManyToManyField
)使用自定义小部件,请确保您未在raw_id_fields
、radio_fields
或autocomplete_fields
中包含该字段的名称。formfield_overrides
不会允许您更改已设置raw_id_fields
、radio_fields
或autocomplete_fields
的关系字段上的小部件。这是因为raw_id_fields
、radio_fields
和autocomplete_fields
隐含了它们自己的自定义小部件。
-
ModelAdmin.
inlines
¶ 另请参见下面的
InlineModelAdmin
对象以及ModelAdmin.get_formsets_with_inlines()
。
-
ModelAdmin.
list_display
¶ 设置
list_display
以控制在管理的更改列表页面上显示哪些字段。示例
list_display = ["first_name", "last_name"]
如果您未设置
list_display
,管理站点将显示一个单列,显示每个对象的__str__()
表示形式。有四种类型的值可用于
list_display
。除了最简单的值,其他值都可以使用display()
装饰器,该装饰器用于自定义字段的显示方式模型字段的名称。例如
class PersonAdmin(admin.ModelAdmin): list_display = ["first_name", "last_name"]
接受一个参数(模型实例)的可调用对象。例如
@admin.display(description="Name") def upper_case_name(obj): return f"{obj.first_name} {obj.last_name}".upper() class PersonAdmin(admin.ModelAdmin): list_display = [upper_case_name]
表示接受一个参数(模型实例)的
ModelAdmin
方法的字符串。例如class PersonAdmin(admin.ModelAdmin): list_display = ["upper_case_name"] @admin.display(description="Name") def upper_case_name(self, obj): return f"{obj.first_name} {obj.last_name}".upper()
表示模型属性或方法(没有任何必需参数)的字符串。例如
from django.contrib import admin from django.db import models class Person(models.Model): name = models.CharField(max_length=50) birthday = models.DateField() @admin.display(description="Birth decade") def decade_born_in(self): decade = self.birthday.year // 10 * 10 return f"{decade}’s" class PersonAdmin(admin.ModelAdmin): list_display = ["name", "decade_born_in"]
关于
list_display
的一些特殊情况如果字段是
ForeignKey
,Django 将显示相关对象的__str__()
。ManyToManyField
字段不受支持,因为这将需要为表中的每一行执行一个单独的 SQL 语句。如果您仍然希望执行此操作,请为您的模型提供一个自定义方法,并将该方法的名称添加到list_display
中。(请参见下文以了解list_display
中的自定义方法的更多信息。)如果字段是
BooleanField
,Django 将显示漂亮的“是”、“否”或“未知”图标,而不是True
、False
或None
。如果给定的字符串是模型、
ModelAdmin
或可调用对象的某个方法,Django 将默认对输出进行 HTML 转义。要转义用户输入并允许您自己的未转义标签,请使用format_html()
。这是一个完整的示例模型
from django.contrib import admin from django.db import models from django.utils.html import format_html class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) color_code = models.CharField(max_length=6) @admin.display def colored_name(self): return format_html( '<span style="color: #{};">{} {}</span>', self.color_code, self.first_name, self.last_name, ) class PersonAdmin(admin.ModelAdmin): list_display = ["first_name", "last_name", "colored_name"]
正如某些示例已经演示的那样,当使用可调用对象、模型方法或
ModelAdmin
方法时,您可以通过使用display()
装饰器包装可调用对象并传递description
参数来自定义列标题。如果字段的值为
None
、空字符串或没有元素的可迭代对象,Django 将显示-
(破折号)。您可以使用AdminSite.empty_value_display
覆盖此值from django.contrib import admin admin.site.empty_value_display = "(None)"
您还可以使用
ModelAdmin.empty_value_display
class PersonAdmin(admin.ModelAdmin): empty_value_display = "unknown"
或在字段级别
class PersonAdmin(admin.ModelAdmin): list_display = ["name", "birth_date_view"] @admin.display(empty_value="unknown") def birth_date_view(self, obj): return obj.birth_date
如果给定的字符串是模型的方法,
ModelAdmin
或返回True
、False
或None
的可调用对象,如果使用display()
装饰器包装该方法并传递boolean
参数(其值设置为True
),Django 将显示一个漂亮的“是”、“否”或“未知”图标from django.contrib import admin from django.db import models class Person(models.Model): first_name = models.CharField(max_length=50) birthday = models.DateField() @admin.display(boolean=True) def born_in_fifties(self): return 1950 <= self.birthday.year < 1960 class PersonAdmin(admin.ModelAdmin): list_display = ["name", "born_in_fifties"]
在
list_display
中,__str__()
方法与任何其他模型方法一样有效,因此这样做完全可以list_display = ["__str__", "some_other_field"]
通常,
list_display
中不是实际数据库字段的元素不能用于排序(因为 Django 在数据库级别执行所有排序)。但是,如果
list_display
的元素表示某个数据库字段,则可以通过对方法使用display()
装饰器来指示此事实,并传递ordering
参数from django.contrib import admin from django.db import models from django.utils.html import format_html class Person(models.Model): first_name = models.CharField(max_length=50) color_code = models.CharField(max_length=6) @admin.display(ordering="first_name") def colored_first_name(self): return format_html( '<span style="color: #{};">{}</span>', self.color_code, self.first_name, ) class PersonAdmin(admin.ModelAdmin): list_display = ["first_name", "colored_first_name"]
上述内容将告诉 Django 在尝试按
colored_first_name
在管理中进行排序时,按first_name
字段进行排序。要使用
ordering
参数指示降序,可以在字段名称前加上连字符前缀。使用上述示例,这将如下所示@admin.display(ordering="-first_name") def colored_first_name(self): ...
ordering
参数支持查询查找,以按相关模型中的值进行排序。此示例在列表显示中包含“作者名”列,并允许按名进行排序class Blog(models.Model): title = models.CharField(max_length=255) author = models.ForeignKey(Person, on_delete=models.CASCADE) class BlogAdmin(admin.ModelAdmin): list_display = ["title", "author", "author_first_name"] @admin.display(ordering="author__first_name") def author_first_name(self, obj): return obj.author.first_name
查询表达式 可与
ordering
参数一起使用from django.db.models import Value from django.db.models.functions import Concat class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) @admin.display(ordering=Concat("first_name", Value(" "), "last_name")) def full_name(self): return self.first_name + " " + self.last_name
list_display
的元素也可以是属性class Person(models.Model): first_name = models.CharField(max_length=50) last_name = models.CharField(max_length=50) @property @admin.display( ordering="last_name", description="Full name of the person", boolean=False, ) def full_name(self): return self.first_name + " " + self.last_name class PersonAdmin(admin.ModelAdmin): list_display = ["full_name"]
请注意,
@property
必须位于@display
之上。如果您使用旧方法(直接设置与显示相关的属性,而不是使用display()
装饰器),请注意必须使用property()
函数,而不是@property
装饰器def my_property(self): return self.first_name + " " + self.last_name my_property.short_description = "Full name of the person" my_property.admin_order_field = "last_name" my_property.boolean = False full_name = property(my_property)
在 Django 5.0 中更改添加了对属性中
boolean
属性的支持。list_display
中的字段名称还将作为 CSS 类出现在 HTML 输出中,形式为column-<field_name>
,位于每个<th>
元素上。例如,这可用于在 CSS 文件中设置列宽。Django 将尝试按此顺序解释
list_display
的每个元素- 模型的字段。
- 一个可调用对象。
- 表示
ModelAdmin
属性的字符串。 - 表示模型属性的字符串。
例如,如果您将
first_name
作为模型字段和ModelAdmin
属性,则将使用模型字段。
-
ModelAdmin.
list_display_links
¶ 使用
list_display_links
控制list_display
中哪些字段以及是否链接到对象的“更改”页面。默认情况下,更改列表页面将链接第一列(
list_display
中指定的第一个字段)到每个项目的更改页面。但list_display_links
允许您更改此设置。将其设置为
None
以完全不显示链接。将其设置为一个字段列表或元组(与
list_display
相同的格式),将这些字段的列转换为链接。您可以指定一个或多个字段。只要这些字段出现在
list_display
中,Django 就不关心链接的字段数量(多少或多少)。唯一的要求是,如果您想以这种方式使用list_display_links
,则必须定义list_display
。
在此示例中,
first_name
和last_name
字段将在更改列表页面上链接。class PersonAdmin(admin.ModelAdmin): list_display = ["first_name", "last_name", "birthday"] list_display_links = ["first_name", "last_name"]
在此示例中,更改列表页面网格将不显示任何链接。
class AuditEntryAdmin(admin.ModelAdmin): list_display = ["timestamp", "message"] list_display_links = None
-
ModelAdmin.
list_editable
¶ 将
list_editable
设置为模型上允许在更改列表页面上进行编辑的字段名称列表。也就是说,list_editable
中列出的字段将作为更改列表页面上的表单小部件显示,允许用户一次编辑和保存多行。注意
list_editable
会以特定方式与其他一些选项交互;您应注意以下规则:
中的任何字段也必须在list_editable
中。您无法编辑未显示的字段!list_display
- 同一字段不能同时列在
和list_editable
中 - 一个字段不能同时是表单和链接。list_display_links
如果违反了其中任何一条规则,您将收到验证错误。
-
ModelAdmin.
list_filter
¶ 设置
以激活管理页面更改列表页右侧的过滤器。list_filter
最简单的
会采用一个字段名称列表或元组来激活过滤,但还有更多高级选项可用。有关详细信息,请参阅 ModelAdmin 列表过滤器。list_filter
-
ModelAdmin.
list_max_show_all
¶ 设置
以控制“显示全部”管理更改列表页上可以显示多少项。仅当结果总数小于或等于此设置时,管理页面才会在更改列表上显示“显示全部”链接。默认情况下,此设置设为list_max_show_all
。200
-
ModelAdmin.
list_per_page
¶ 设置
以控制每个分页管理更改列表页上显示多少项。默认情况下,此设置设为list_per_page
。100
将
list_select_related
设置为告诉 Django 在检索管理员更改列表页面上的对象列表时使用select_related()
。这可以为你节省大量数据库查询。该值应为布尔值、列表或元组。默认值为
False
。当值为
True
时,将始终调用select_related()
。当值设置为False
时,Django 将查看list_display
,并在存在任何ForeignKey
时调用select_related()
。如果你需要更精细的控制,请使用元组(或列表)作为
list_select_related
的值。空元组将阻止 Django 调用select_related()
。任何其他元组都将直接作为参数传递给select_related
。例如class ArticleAdmin(admin.ModelAdmin): list_select_related = ["author", "category"]
将调用
select_related('author', 'category')
。如果你需要根据请求指定动态值,则可以实现
get_list_select_related()
方法。注意
ModelAdmin
在更改列表的QuerySet
上已经调用select_related()
时,将忽略此属性。
-
ModelAdmin.
ordering
¶ 设置
ordering
以指定对象列表在 Django 管理视图中排序的方式。这应为与模型的ordering
参数格式相同的列表或元组。如果未提供此项,Django 管理将使用模型的默认排序。
如果您需要指定动态顺序(例如取决于用户或语言),您可以实现
get_ordering()
方法。排序方面的性能考虑
为了确保结果的确定性排序,如果找不到可提供全部排序的单个或唯一一起的字段集,则变更列表会将
pk
添加到排序中。例如,如果默认排序按非唯一的
name
字段进行,则变更列表按name
和pk
进行排序。如果您有大量行并且没有对name
和pk
建立索引,则这可能会表现不佳。
-
ModelAdmin.
paginator
¶ 用于分页的分页器类。默认情况下,使用
django.core.paginator.Paginator
。如果自定义分页器类的构造器接口与django.core.paginator.Paginator
不同,您还需要为ModelAdmin.get_paginator()
提供实现。
-
ModelAdmin.
prepopulated_fields
¶ 将
prepopulated_fields
设置为将字段名称映射到它应从中预填充的字段的字典class ArticleAdmin(admin.ModelAdmin): prepopulated_fields = {"slug": ["title"]}
设置后,给定字段将使用一些 JavaScript 从分配的字段中填充。此功能的主要用途是从一个或多个其他字段自动生成
SlugField
字段的值。生成的值通过连接源字段的值产生,然后将该结果转换为有效的 slug(例如,用破折号替换空格,并将 ASCII 字母小写)。预填充字段在值保存后不会被 JavaScript 修改。通常不希望 slug 发生更改(如果 slug 在其中使用,则会导致对象的 URL 更改)。
prepopulated_fields
不接受DateTimeField
、ForeignKey
、OneToOneField
和ManyToManyField
字段。
-
ModelAdmin.
preserve_filters
¶ 默认情况下,在创建、编辑或删除对象后,应用的筛选器将保留在列表视图中。你可以通过将此属性设置为
False
来清除筛选器。
-
ModelAdmin.
show_facets
¶ - Django 5.0 中的新增功能。
控制是否在管理更改列表中为筛选器显示分类计数。默认为
ShowFacets.ALLOW
。显示时,分类计数将根据当前应用的筛选器进行更新。
-
class
ShowFacets
¶ - Django 5.0 中的新增功能。
为
ModelAdmin.show_facets
允许的值的枚举。-
ALWAYS
¶ 始终显示分类计数。
-
ALLOW
¶ 当提供
_facets
查询字符串参数时,显示分类计数。
-
NEVER
¶ 从不显示小分类计数。
-
将
show_facets
设置为所需的ShowFacets
值。例如,要在不提供查询参数的情况下始终显示小分类计数from django.contrib import admin class MyModelAdmin(admin.ModelAdmin): ... # Have facets always shown for this model admin. show_facets = admin.ShowFacets.ALWAYS
小分类的性能注意事项
启用小分类过滤器将根据过滤器数量增加管理变更列表页面上的查询数量。这些查询可能会导致性能问题,特别是对于大型数据集。在这些情况下,可以将
show_facets
设置为ShowFacets.NEVER
以完全禁用小分类。 -
class
-
ModelAdmin.
radio_fields
¶ 默认情况下,Django 的管理界面使用选择框界面 (<select>) 来处理
ForeignKey
或设置了choices
的字段。如果某个字段存在于radio_fields
中,Django 将改用单选按钮界面。假设group
是Person
模型上的ForeignKey
class PersonAdmin(admin.ModelAdmin): radio_fields = {"group": admin.VERTICAL}
你可以选择使用
HORIZONTAL
或VERTICAL
来自django.contrib.admin
模块。除非某个字段是
ForeignKey
或设置了choices
,否则不要将其包含在radio_fields
中。
-
ModelAdmin.
autocomplete_fields
¶ autocomplete_fields
是一个ForeignKey
和/或ManyToManyField
字段列表,你希望将其更改为 Select2 自动完成输入。默认情况下,管理员使用选择框界面 (
<select>
) 来处理这些字段。有时,您不想承担在下拉菜单中显示所有相关实例的开销。Select2 输入看起来与默认输入类似,但它带有异步加载选项的搜索功能。如果相关模型有很多实例,这将更快且更易于用户使用。
您必须在相关对象的
ModelAdmin
中定义search_fields
,因为自动完成搜索使用它。为避免未经授权的数据泄露,用户必须拥有相关对象的
view
或change
权限才能使用自动完成。结果的排序和分页由相关
ModelAdmin
的get_ordering()
和get_paginator()
方法控制。在以下示例中,
ChoiceAdmin
具有ForeignKey
的自动完成字段,指向Question
。结果根据question_text
字段进行筛选,并按date_created
字段排序class QuestionAdmin(admin.ModelAdmin): ordering = ["date_created"] search_fields = ["question_text"] class ChoiceAdmin(admin.ModelAdmin): autocomplete_fields = ["question"]
大数据集的性能注意事项
使用
ModelAdmin.ordering
进行排序可能会导致性能问题,因为对大型查询集进行排序会很慢。此外,如果您的搜索字段包含未由数据库编入索引的字段,则在极大的表上可能会遇到性能不佳的情况。
对于这些情况,最好编写自己的
ModelAdmin.get_search_results()
实现,使用全文索引搜索。您可能还希望在非常大的表上更改
Paginator
,因为默认分页器始终执行count()
查询。例如,您可以覆盖Paginator.count
属性的默认实现。
-
ModelAdmin.
raw_id_fields
¶ 默认情况下,Django 的管理界面对
ForeignKey
字段使用选择框界面 (<select>)。有时您不希望承担必须选择所有相关实例以在下拉菜单中显示的开销。raw_id_fields
是一个字段列表,您希望将其更改为Input
小组件,用于ForeignKey
或ManyToManyField
class ArticleAdmin(admin.ModelAdmin): raw_id_fields = ["newspaper"]
如果字段是
ForeignKey
,则raw_id_fields
Input
小组件应包含一个主键;如果字段是ManyToManyField
,则应包含一个逗号分隔的值列表。raw_id_fields
小组件在字段旁边显示一个放大镜按钮,允许用户搜索并选择一个值
-
ModelAdmin.
readonly_fields
¶ 默认情况下,管理员会将所有字段显示为可编辑。此选项中的任何字段(应为
list
或tuple
)将按原样显示其数据且不可编辑;它们还从用于创建和编辑的ModelForm
中排除。请注意,在指定ModelAdmin.fields
或ModelAdmin.fieldsets
时,必须显示只读字段(否则将忽略它们)。如果在未通过
ModelAdmin.fields
或ModelAdmin.fieldsets
定义显式排序的情况下使用readonly_fields
,它们将在所有可编辑字段之后最后添加。只读字段不仅可以显示模型字段中的数据,还可以显示模型方法或
ModelAdmin
类本身的方法的输出。这与ModelAdmin.list_display
的行为非常相似。这提供了一种使用管理员界面来提供有关所编辑对象状态的反馈的方法,例如from django.contrib import admin from django.utils.html import format_html_join from django.utils.safestring import mark_safe class PersonAdmin(admin.ModelAdmin): readonly_fields = ["address_report"] # description functions like a model field's verbose_name @admin.display(description="Address") def address_report(self, instance): # assuming get_full_address() returns a list of strings # for each line of the address and you want to separate each # line by a linebreak return format_html_join( mark_safe("<br>"), "{}", ((line,) for line in instance.get_full_address()), ) or mark_safe("<span class='errors'>I can't determine this address.</span>")
-
ModelAdmin.
save_as
¶ 将
save_as
设置为True
,以在管理更改表单中启用“另存为新”功能。通常,对象有三个保存选项:“保存”、“保存并继续编辑”和“保存并添加另一个”。如果
save_as
为True
,“保存并添加另一个”将被“另存为新”按钮取代,该按钮会创建一个新对象(具有新 ID),而不是更新现有对象。默认情况下,
save_as
设置为False
。
-
ModelAdmin.
save_as_continue
¶ 当
save_as=True
时,保存新对象后的默认重定向是该对象的更改视图。如果将save_as_continue=False
设置为False
,则重定向将是更改列表视图。默认情况下,
save_as_continue
设置为True
。
-
ModelAdmin.
save_on_top
¶ 将
save_on_top
设置为True
,以在管理更改表单顶部添加保存按钮。通常,保存按钮仅出现在表单底部。如果将
save_on_top
设置为True
,则按钮将同时出现在顶部和底部。默认情况下,
save_on_top
设置为False
。
-
ModelAdmin.
search_fields
¶ 设置
search_fields
以在管理更改列表页面上启用搜索框。这应设置为将在该文本框中提交搜索查询时进行搜索的字段名称列表。这些字段应为某种文本字段,例如
CharField
或TextField
。您还可以使用查找 API “follow” 符号在ForeignKey
或ManyToManyField
上执行相关查找search_fields = ["foreign_key__related_fieldname"]
例如,如果您有一个带有作者的博客条目,则以下定义将允许通过作者的电子邮件地址搜索博客条目
search_fields = ["user__email"]
当有人在管理搜索框中进行搜索时,Django 会将搜索查询拆分为单词,并返回包含每个单词的所有对象,不区分大小写(使用
icontains
查找),其中每个单词必须至少包含在search_fields
中的一个单词中。例如,如果search_fields
设置为['first_name', 'last_name']
,并且用户搜索john lennon
,Django 将执行等效于此 SQLWHERE
子句WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%') AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')
搜索查询可以包含带空格的引号短语。例如,如果用户搜索
"john winston"
或'john winston'
,Django 将执行等效于此 SQLWHERE
子句WHERE (first_name ILIKE '%john winston%' OR last_name ILIKE '%john winston%')
如果您不想使用
icontains
作为查找,您可以通过将它附加到字段来使用任何查找。例如,您可以通过将search_fields
设置为['first_name__exact']
来使用exact
。还提供了一些(较旧的)用于指定字段查找的快捷方式。您可以在
search_fields
中的前缀字段带有以下字符,并且它等效于向字段添加__<lookup>
前缀 查找 ^ istartswith
= iexact
@ search
无 icontains
如果您需要自定义搜索,可以使用
ModelAdmin.get_search_results()
提供其他或备用的搜索行为。
-
ModelAdmin.
search_help_text
¶ 设置
search_help_text
以指定搜索框的描述性文本,该文本将显示在搜索框下方。
-
ModelAdmin.
show_full_result_count
¶ 设置
show_full_result_count
以控制是否在经过筛选的管理页面上显示对象的完整计数(例如99 results (103 total)
)。如果此选项设置为False
,则会显示类似99 results (Show all)
的文本。默认情况下
show_full_result_count=True
会生成一个查询以对表执行完整计数,如果表包含大量行,这可能会很昂贵。
-
ModelAdmin.
sortable_by
¶ 默认情况下,更改列表页面允许按所有模型字段(以及使用
ordering
参数的display()
装饰器或具有admin_order_field
属性)进行排序,这些属性在list_display
中指定。如果您想禁用某些列的排序,请将
sortable_by
设置为list_display
子集的集合(例如list
、tuple
或set
),您希望它们可排序。空集合禁用所有列的排序。如果您需要动态指定此列表,请改而实现
get_sortable_by()
方法。
-
ModelAdmin.
view_on_site
¶ 设置
view_on_site
以控制是否显示“在网站上查看”链接。此链接应将您带到一个 URL,您可以在其中显示已保存的对象。此值可以是布尔标志或可调用对象。如果为
True
(默认值),则对象的get_absolute_url()
方法将用于生成 URL。如果你的模型有一个
get_absolute_url()
方法,但你不想让“在网站上查看”按钮出现,你只需要将view_on_site
设置为False
from django.contrib import admin class PersonAdmin(admin.ModelAdmin): view_on_site = False
如果它是一个可调用对象,它接受模型实例作为参数。例如
from django.contrib import admin from django.urls import reverse class PersonAdmin(admin.ModelAdmin): def view_on_site(self, obj): url = reverse("person-detail", kwargs={"slug": obj.slug}) return "https://example.com" + url
自定义模板选项¶
覆盖管理模板 部分描述了如何覆盖或扩展默认管理模板。使用以下选项覆盖 ModelAdmin
视图使用的默认模板
-
ModelAdmin.
add_form_template
¶ 自定义模板的路径,由
add_view()
使用。
-
ModelAdmin.
change_form_template
¶ 自定义模板的路径,由
change_view()
使用。
-
ModelAdmin.
change_list_template
¶ 自定义模板的路径,由
changelist_view()
使用。
-
ModelAdmin.
delete_confirmation_template
¶ 自定义模板的路径,由
delete_view()
使用,用于在删除一个或多个对象时显示确认页面。
-
ModelAdmin.
delete_selected_confirmation_template
¶ 自定义模板的路径,由
delete_selected
操作方法使用,用于在删除一个或多个对象时显示确认页面。请参阅 操作文档。
-
ModelAdmin.
object_history_template
¶ 自定义模板的路径,由
history_view()
使用。
-
ModelAdmin.
popup_response_template
¶ 自定义模板的路径,由
response_add()
、response_change()
和response_delete()
使用。
ModelAdmin
方法¶
警告
覆盖 ModelAdmin.save_model()
和 ModelAdmin.delete_model()
时,代码必须保存/删除对象。它们并非用于否决目的,而是允许你执行额外的操作。
-
ModelAdmin.
save_model
(request, obj, form, change)¶ 方法
save_model
提供HttpRequest
、模型实例、ModelForm
实例以及一个布尔值,该布尔值基于对象是添加还是更改。重写此方法允许执行预保存或后保存操作。调用super().save_model()
以使用Model.save()
保存对象。例如,在保存之前将
request.user
附加到对象from django.contrib import admin class ArticleAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): obj.user = request.user super().save_model(request, obj, form, change)
-
ModelAdmin.
delete_model
(request, obj)¶ 方法
delete_model
提供HttpRequest
和模型实例。重写此方法允许执行预删除或后删除操作。调用super().delete_model()
以使用Model.delete()
删除对象。
-
ModelAdmin.
delete_queryset
(request, queryset)¶ 方法
delete_queryset()
提供HttpRequest
和要删除的对象的QuerySet
。重写此方法以自定义“删除选定对象”操作 的删除过程。
-
ModelAdmin.
save_formset
(request, form, formset, change)¶ 方法
save_formset
提供HttpRequest
、父ModelForm
实例以及一个布尔值,该布尔值基于对象是添加还是更改父对象。例如,将
request.user
附加到每个已更改的表单集模型实例class ArticleAdmin(admin.ModelAdmin): def save_formset(self, request, form, formset, change): instances = formset.save(commit=False) for obj in formset.deleted_objects: obj.delete() for instance in instances: instance.user = request.user instance.save() formset.save_m2m()
另请参见 在表单集中保存对象。
-
ModelAdmin.
get_ordering
(request)¶ get_ordering
方法将request
作为参数,并应返回类似于ordering
属性的list
或tuple
以进行排序。例如class PersonAdmin(admin.ModelAdmin): def get_ordering(self, request): if request.user.is_superuser: return ["name", "rank"] else: return ["name"]
-
ModelAdmin.
get_search_results
(request, queryset, search_term)¶ get_search_results
方法将显示的对象列表修改为与提供的搜索词匹配的对象列表。它接受请求、应用当前筛选器的查询集以及用户提供的搜索词。它返回一个元组,其中包含一个已修改以实现搜索的查询集,以及一个指示结果可能包含重复项的布尔值。默认实现搜索
ModelAdmin.search_fields
中命名的字段。可以使用您自己的自定义搜索方法覆盖此方法。例如,您可能希望按整数字段搜索,或使用外部工具,例如 Solr 或 Haystack。您必须确定由您的搜索方法实现的查询集更改是否会在结果中引入重复项,并在返回值的第二个元素中返回
True
。例如,要按
name
和age
搜索,可以使用class PersonAdmin(admin.ModelAdmin): list_display = ["name", "age"] search_fields = ["name"] def get_search_results(self, request, queryset, search_term): queryset, may_have_duplicates = super().get_search_results( request, queryset, search_term, ) try: search_term_as_int = int(search_term) except ValueError: pass else: queryset |= self.model.objects.filter(age=search_term_as_int) return queryset, may_have_duplicates
此实现比
search_fields = ('name', '=age')
更有效率,后者会导致对数字字段进行字符串比较,例如... OR UPPER("polls_choice"."votes"::text) = UPPER('4')
在 PostgreSQL 上。
save_related
方法给出了HttpRequest
、父ModelForm
实例、内联表单集列表和一个基于父对象是正在添加还是正在更改的布尔值。在此,您可以对与父对象相关的对象执行任何预保存或后保存操作。请注意,此时父对象及其表单已保存。
-
ModelAdmin.
get_autocomplete_fields
(request)¶ get_autocomplete_fields()
方法给出了HttpRequest
,并且应返回一个list
或tuple
的字段名称,这些字段名称将使用自动完成小部件显示,如上文ModelAdmin.autocomplete_fields
部分所述。
-
ModelAdmin.
get_readonly_fields
(request, obj=None)¶ 方法
get_readonly_fields
给定HttpRequest
和正在编辑的obj
(或在添加表单上的None
),并且预期返回一个list
或tuple
的字段名称,这些字段名称将显示为只读,如上文ModelAdmin.readonly_fields
部分中所述。
-
ModelAdmin.
get_prepopulated_fields
(request, obj=None)¶ 方法
get_prepopulated_fields
给定HttpRequest
和正在编辑的obj
(或在添加表单上的None
),并且预期返回一个dictionary
,如上文ModelAdmin.prepopulated_fields
部分中所述。
-
ModelAdmin.
get_list_display
(request)¶ 方法
get_list_display
给定HttpRequest
,并且预期返回一个list
或tuple
的字段名称,这些字段名称将显示在变更列表视图中,如上文ModelAdmin.list_display
部分中所述。
-
ModelAdmin.
get_list_display_links
(request, list_display)¶ 将
get_list_display_links
方法赋予HttpRequest
和list
或tuple
,由ModelAdmin.get_list_display()
返回。期望返回None
或list
或tuple
,其中包含变更列表中字段名称,该字段名称将链接到变更视图,如ModelAdmin.list_display_links
部分中所述。
-
ModelAdmin.
get_exclude
(request, obj=None)¶ 将
get_exclude
方法赋予HttpRequest
和正在编辑的obj
(或在添加表单中为None
),期望返回字段列表,如ModelAdmin.exclude
中所述。
-
ModelAdmin.
get_fields
(request, obj=None)¶ 将
get_fields
方法赋予HttpRequest
和正在编辑的obj
(或在添加表单中为None
),期望返回字段列表,如上文ModelAdmin.fields
部分中所述。
-
ModelAdmin.
get_fieldsets
(request, obj=None)¶ get_fieldsets
方法给出了HttpRequest
和正在编辑的obj
(或在添加表单上的None
),并期望返回一个 2 元组列表,其中每个 2 元组表示管理表单页面上的<fieldset>
,如上文ModelAdmin.fieldsets
部分所述。
-
ModelAdmin.
get_list_filter
(request)¶ get_list_filter
方法给出了HttpRequest
,并期望返回与list_filter
属性相同的序列类型。
get_list_select_related
方法给出了HttpRequest
,并且应返回布尔值或列表,就像ModelAdmin.list_select_related
所做的那样。
-
ModelAdmin.
get_search_fields
(request)¶ get_search_fields
方法给出了HttpRequest
,并期望返回与search_fields
属性相同的序列类型。
-
ModelAdmin.
get_sortable_by
(request)¶ get_sortable_by()
方法会传递HttpRequest
,并应返回一个集合(例如list
、tuple
或set
),其中包含更改列表页面中可排序的字段名称。它的默认实现会返回
sortable_by
(如果已设置),否则会推迟到get_list_display()
。例如,要防止一个或多个列可排序
class PersonAdmin(admin.ModelAdmin): def get_sortable_by(self, request): return {*self.get_list_display(request)} - {"rank"}
-
ModelAdmin.
get_inline_instances
(request, obj=None)¶ get_inline_instances
方法提供了HttpRequest
和正在编辑的obj
(或在添加表单中为None
),并应返回list
或InlineModelAdmin
对象的tuple
,如下文InlineModelAdmin
部分所述。例如,以下内容将返回不基于添加、更改、删除和查看权限的默认筛选的内联class MyModelAdmin(admin.ModelAdmin): inlines = [MyInline] def get_inline_instances(self, request, obj=None): return [inline(self.model, self.admin_site) for inline in self.inlines]
如果您覆盖此方法,请确保返回的内联是
inlines
中定义的类的实例,否则在添加相关对象时可能会遇到“错误的请求”错误。
-
ModelAdmin.
get_inlines
(request, obj)¶ get_inlines
方法提供了HttpRequest
和正在编辑的obj
(或在添加表单中为None
),并应返回内联的可迭代对象。您可以覆盖此方法以根据请求或模型实例动态添加内联,而不是在ModelAdmin.inlines
中指定内联。
-
ModelAdmin.
get_urls
()¶ 在
ModelAdmin
上的get_urls
方法以与 URLconf 相同的方式返回要用于该 ModelAdmin 的 URL。因此,你可以使用AdminSite.admin_view()
包装器在视图中扩展它们,如 URL 调度程序 中所述from django.contrib import admin from django.template.response import TemplateResponse from django.urls import path class MyModelAdmin(admin.ModelAdmin): def get_urls(self): urls = super().get_urls() my_urls = [path("my_view/", self.admin_site.admin_view(self.my_view))] return my_urls + urls def my_view(self, request): # ... context = dict( # Include common variables for rendering the admin template. self.admin_site.each_context(request), # Anything else you want in the context... key=value, ) return TemplateResponse(request, "sometemplate.html", context)
如果你想使用管理布局,请从
admin/base_site.html
扩展{% extends "admin/base_site.html" %} {% block content %} ... {% endblock %}
注意
请注意
self.my_view
函数是如何包装在self.admin_site.admin_view
中的。这一点很重要,因为它确保了两件事- 运行权限检查,确保只有活跃的工作人员用户才能访问视图。
django.views.decorators.cache.never_cache()
装饰器用于防止缓存,确保返回的信息是最新的。
注意
请注意,自定义模式包含在常规管理 URL 之前:管理 URL 模式非常宽松,几乎可以匹配任何内容,因此你通常希望将自定义 URL 添加到内置 URL 之前。
在此示例中,
my_view
将在/admin/myapp/mymodel/my_view/
处访问(假设管理 URL 包含在/admin/
中。)如果页面可缓存,但你仍然希望执行权限检查,则可以将
cacheable=True
参数传递给AdminSite.admin_view()
path("my_view/", self.admin_site.admin_view(self.my_view, cacheable=True))
ModelAdmin
视图具有model_admin
属性。其他AdminSite
视图具有admin_site
属性。
-
ModelAdmin.
get_form
(request, obj=None, **kwargs)¶ 返回
ModelForm
类,用于在管理添加和更改视图中,请参见add_view()
和change_view()
。基本实现使用
modelform_factory()
对form
进行子类化,由fields
和exclude
等属性修改。因此,例如,如果您想为超级用户提供其他字段,则可以像这样换入不同的基本表单class MyModelAdmin(admin.ModelAdmin): def get_form(self, request, obj=None, **kwargs): if request.user.is_superuser: kwargs["form"] = MySuperuserForm return super().get_form(request, obj, **kwargs)
您还可以直接返回自定义
ModelForm
类。
-
ModelAdmin.
get_formsets_with_inlines
(request, obj=None)¶ 生成用于在管理添加和更改视图中使用的 (
FormSet
,InlineModelAdmin
) 对。例如,如果你想仅在更改视图中显示特定内联,你可以按如下方式覆盖
get_formsets_with_inlines
class MyModelAdmin(admin.ModelAdmin): inlines = [MyInline, SomeOtherInline] def get_formsets_with_inlines(self, request, obj=None): for inline in self.get_inline_instances(request, obj): # hide MyInline in the add view if not isinstance(inline, MyInline) or obj is not None: yield inline.get_formset(request, obj), inline
-
ModelAdmin.
formfield_for_foreignkey
(db_field, request, **kwargs)¶ 在
ModelAdmin
上的formfield_for_foreignkey
方法允许你覆盖外键字段的默认表单字段。例如,根据用户返回此外键字段的对象子集class MyModelAdmin(admin.ModelAdmin): def formfield_for_foreignkey(self, db_field, request, **kwargs): if db_field.name == "car": kwargs["queryset"] = Car.objects.filter(owner=request.user) return super().formfield_for_foreignkey(db_field, request, **kwargs)
这使用
HttpRequest
实例来过滤Car
外键字段,以仅显示User
实例拥有的汽车。对于更复杂的过滤器,你可以使用
ModelForm.__init__()
方法根据模型的instance
进行过滤(请参阅 处理关系的字段)。例如class CountryAdminForm(forms.ModelForm): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.fields["capital"].queryset = self.instance.cities.all() class CountryAdmin(admin.ModelAdmin): form = CountryAdminForm
-
ModelAdmin.
formfield_for_manytomany
(db_field, request, **kwargs)¶ 与
formfield_for_foreignkey
方法类似,formfield_for_manytomany
方法可以被覆盖以更改多对多字段的默认表单字段。例如,如果一个所有者可以拥有多辆车,而汽车可以属于多个所有者(多对多关系),则可以过滤Car
外键字段,以仅显示User
所拥有的汽车class MyModelAdmin(admin.ModelAdmin): def formfield_for_manytomany(self, db_field, request, **kwargs): if db_field.name == "cars": kwargs["queryset"] = Car.objects.filter(owner=request.user) return super().formfield_for_manytomany(db_field, request, **kwargs)
-
ModelAdmin.
formfield_for_choice_field
(db_field, request, **kwargs)¶ 与
formfield_for_foreignkey
和formfield_for_manytomany
方法类似,formfield_for_choice_field
方法可以被覆盖以更改已声明选项的字段的默认表单字段。例如,如果超级用户可用的选项应与普通工作人员可用的选项不同,则可以按如下方式进行class MyModelAdmin(admin.ModelAdmin): def formfield_for_choice_field(self, db_field, request, **kwargs): if db_field.name == "status": kwargs["choices"] = [ ("accepted", "Accepted"), ("denied", "Denied"), ] if request.user.is_superuser: kwargs["choices"].append(("ready", "Ready for deployment")) return super().formfield_for_choice_field(db_field, request, **kwargs)
choices
限制在表单字段上设置的任何
choices
属性都将仅限于表单字段。如果模型上的相应字段设置了选项,则提供给表单的选项必须是这些选项的有效子集,否则在保存之前验证模型本身时,表单提交将因ValidationError
而失败。
-
ModelAdmin.
get_changelist
(request, **kwargs)¶ 返回用于列出的
Changelist
类。默认情况下,使用django.contrib.admin.views.main.ChangeList
。通过继承此类,可以更改列表的行为。
-
ModelAdmin.
get_changelist_form
(request, **kwargs)¶ 返回
ModelForm
类,用于更改列表页面的Formset
。例如,要使用自定义表单,from django import forms class MyForm(forms.ModelForm): pass class MyModelAdmin(admin.ModelAdmin): def get_changelist_form(self, request, **kwargs): return MyForm
-
ModelAdmin.
get_changelist_formset
(request, **kwargs)¶ 如果使用
list_editable
,则返回 ModelFormSet 类,用于更改列表页面。例如,要使用自定义表单集,from django.forms import BaseModelFormSet class MyAdminFormSet(BaseModelFormSet): pass class MyModelAdmin(admin.ModelAdmin): def get_changelist_formset(self, request, **kwargs): kwargs["formset"] = MyAdminFormSet return super().get_changelist_formset(request, **kwargs)
-
ModelAdmin.
lookup_allowed
(lookup, value, request)¶ 更改列表页面中的对象可以使用 URL 查询字符串中的查找器进行筛选。例如,
list_filter
的工作方式就是这样。查找器类似于QuerySet.filter()
中使用的查找器(例如[email protected]
)。由于查询字符串中的查找器可以由用户操作,因此必须对其进行清理以防止未经授权的数据泄露。lookup_allowed()
方法会从查询字符串(例如'user__email'
)获得查找器路径,获得相应的 value(例如'[email protected]'
),获得请求,并返回一个布尔值,指示是否允许使用参数筛选更改列表的QuerySet
。如果lookup_allowed()
返回False
,则会引发DisallowedModelAdminLookup
(SuspiciousOperation
的子类)。默认情况下,
lookup_allowed()
允许访问模型的本地字段、list_filter
中使用的字段路径(但不是get_list_filter()
中的路径),以及limit_choices_to
在raw_id_fields
中正常运行所需的查找器。覆盖此方法以自定义
ModelAdmin
子类的允许查找器。在 Django 5.0 中更改已添加
request
参数。
-
ModelAdmin.
has_view_permission
(request, obj=None)¶ 如果允许查看
obj
,则应返回True
,否则返回False
。如果 obj 为None
,则应返回True
或False
,以指示是否通常允许查看此类型的对象(例如,False
将被解释为当前用户不允许查看此类型的任何对象)。如果用户具有“更改”或“查看”权限,则默认实现返回
True
。
-
ModelAdmin.
has_add_permission
(request)¶ 如果允许添加对象,则应返回
True
,否则返回False
。
-
ModelAdmin.
has_change_permission
(request, obj=None)¶ 如果允许编辑
obj
,则应返回True
,否则返回False
。如果obj
为None
,则应返回True
或False
以指示通常是否允许编辑此类型的对象(例如,False
将被解释为当前用户不允许编辑此类型的任何对象)。
-
ModelAdmin.
has_delete_permission
(request, obj=None)¶ 如果允许删除
obj
,则应返回True
,否则返回False
。如果obj
为None
,则应返回True
或False
以指示通常是否允许删除此类型的对象(例如,False
将被解释为当前用户不允许删除此类型的任何对象)。
-
ModelAdmin.
has_module_permission
(request)¶ 如果允许在管理索引页上显示模块和访问模块的索引页,则应返回
True
,否则返回False
。默认情况下使用User.has_module_perms()
。覆盖它不会限制对视图、添加、更改或删除视图的访问权限,has_view_permission()
、has_add_permission()
、has_change_permission()
和has_delete_permission()
应用于此。
-
ModelAdmin.
get_queryset
(request)¶ get_queryset
方法在ModelAdmin
上返回QuerySet
,其中包含管理站点可以编辑的所有模型实例。覆盖此方法的一个用例是显示登录用户拥有的对象class MyModelAdmin(admin.ModelAdmin): def get_queryset(self, request): qs = super().get_queryset(request) if request.user.is_superuser: return qs return qs.filter(author=request.user)
-
ModelAdmin.
message_user
(request, message, level=messages.INFO, extra_tags='', fail_silently=False)¶ 使用
django.contrib.messages
后端向用户发送消息。请参阅 自定义 ModelAdmin 示例。关键字参数允许您更改消息级别,添加额外的 CSS 标记,或在未安装
contrib.messages
框架时静默失败。这些关键字参数与django.contrib.messages.add_message()
的参数匹配,有关更多详细信息,请参阅该函数的文档。一个区别是,除了整数/常量之外,还可以将级别作为字符串标签传递。
-
ModelAdmin.
get_paginator
(request, queryset, per_page, orphans=0, allow_empty_first_page=True)¶ 返回要用于此视图的分词器实例。默认情况下,实例化
paginator
的实例。
-
ModelAdmin.
response_add
(request, obj, post_url_continue=None)¶ 确定
HttpResponse
用于add_view()
阶段。response_add
在提交管理表单后以及在对象和所有相关实例创建并保存之后被调用。你可以覆盖它以在创建对象后更改默认行为。
-
ModelAdmin.
response_change
(request, obj)¶ 确定
HttpResponse
用于change_view()
阶段。response_change
在提交管理表单后以及在对象和所有相关实例保存之后被调用。你可以覆盖它以在更改对象后更改默认行为。
-
ModelAdmin.
response_delete
(request, obj_display, obj_id)¶ 确定
HttpResponse
用于delete_view()
阶段。response_delete
在删除对象后被调用。你可以覆盖它以在删除对象后更改默认行为。obj_display
是一个字符串,其中包含已删除对象的名称。obj_id
是用于检索要删除的对象的序列化标识符。
-
ModelAdmin.
get_formset_kwargs
(request, obj, inline, prefix)¶ 一个用于自定义传递给表单集构造函数的关键字参数的钩子。例如,要将
request
传递给表单集表单class MyModelAdmin(admin.ModelAdmin): def get_formset_kwargs(self, request, obj, inline, prefix): return { **super().get_formset_kwargs(request, obj, inline, prefix), "form_kwargs": {"request": request}, }
您还可以使用它为表单集表单设置
initial
。
-
ModelAdmin.
get_changeform_initial_data
(request)¶ 用于管理更改表单上初始数据的钩子。默认情况下,字段的初始值来自
GET
参数。例如,?name=initial_value
将把name
字段的初始值设置为initial_value
。此方法应返回一个形式为
{'fieldname': 'fieldval'}
的字典def get_changeform_initial_data(self, request): return {"name": "custom_initial_value"}
-
ModelAdmin.
get_deleted_objects
(objs, request)¶ 用于自定义
delete_view()
和“删除所选”操作 的删除过程的钩子。objs
参数是要删除的对象的同类可迭代对象(QuerySet
或模型实例列表),request
是HttpRequest
。此方法必须返回
(deleted_objects, model_count, perms_needed, protected)
的 4 元组。deleted_objects
是一个字符串列表,表示将要删除的所有对象。如果存在任何要删除的关联对象,则列表将被嵌套并包含这些关联对象。该列表使用unordered_list
过滤器在模板中进行格式化。model_count
是一个字典,将每个模型的verbose_name_plural
映射到将要删除的对象数。perms_needed
是一个集合,其中包含用户无权删除的模型的verbose_name
。protected
是一个字符串列表,表示所有无法删除的受保护关联对象。该列表显示在模板中。
其他方法¶
-
ModelAdmin.
add_view
(request, form_url='', extra_context=None)¶ 模型实例添加页面的 Django 视图。请参阅下面的注释。
-
ModelAdmin.
change_view
(request, object_id, form_url='', extra_context=None)¶ 模型实例编辑页面的 Django 视图。请参阅下面的注释。
-
ModelAdmin.
changelist_view
(request, extra_context=None)¶ 模型实例更改列表/操作页面的 Django 视图。请参阅下面的注释。
-
ModelAdmin.
delete_view
(request, object_id, extra_context=None)¶ 模型实例删除确认页面的 Django 视图。请参阅下面的注释。
-
ModelAdmin.
history_view
(request, object_id, extra_context=None)¶ 用于显示给定模型实例的修改历史记录的页面的 Django 视图。
与上一部分中详述的挂钩类型 ModelAdmin
方法不同,这五个方法实际上被设计为从管理应用程序 URL 调度处理程序调用为 Django 视图,以呈现处理模型实例 CRUD 操作的页面。因此,完全覆盖这些方法将显著改变管理应用程序的行为。
覆盖这些方法的一个常见原因是扩充提供给呈现视图的模板的上下文数据。在以下示例中,覆盖更改视图,以便为呈现的模板提供一些原本不可用的额外映射数据
class MyModelAdmin(admin.ModelAdmin):
# A template for a very customized change view:
change_form_template = "admin/myapp/extras/openstreetmap_change_form.html"
def get_osm_info(self):
# ...
pass
def change_view(self, request, object_id, form_url="", extra_context=None):
extra_context = extra_context or {}
extra_context["osm_data"] = self.get_osm_info()
return super().change_view(
request,
object_id,
form_url,
extra_context=extra_context,
)
这些视图返回 TemplateResponse
实例,它允许您在呈现之前轻松自定义响应数据。有关更多详细信息,请参阅 TemplateResponse 文档。
ModelAdmin
资产定义¶
有时您希望向添加/更改视图添加一些 CSS 和/或 JavaScript。这可以通过在 ModelAdmin
上使用 Media
内部类来实现
class ArticleAdmin(admin.ModelAdmin):
class Media:
css = {
"all": ["my_styles.css"],
}
js = ["my_code.js"]
staticfiles 应用程序 会将 STATIC_URL
(或 MEDIA_URL
,如果 STATIC_URL
为 None
)预置到任何资产路径。与 表单上的常规资产定义 相同的规则适用。
jQuery¶
Django 管理 JavaScript 使用 jQuery 库。
为了避免与用户提供的脚本或库发生冲突,Django 的 jQuery(版本 3.7.1)命名空间为 django.jQuery
。如果您想在自己的管理 JavaScript 中使用 jQuery 而无需包含第二个副本,您可以在变更列表和添加/编辑视图中使用 django.jQuery
对象。此外,依赖于 django.jQuery
的您自己的管理表单或小部件必须在 声明表单媒体资产 时指定 js=['admin/js/jquery.init.js', …]
。
jQuery 已从 3.6.0 升级到 3.6.4。
jQuery 已从 3.6.4 升级到 3.7.1。
ModelAdmin
类默认情况下需要 jQuery,因此无需将 jQuery 添加到 ModelAdmin
的媒体资源列表中,除非您有特殊需求。例如,如果您需要 jQuery 库位于全局名称空间中(例如,当使用第三方 jQuery 插件时)或如果您需要较新版本的 jQuery,您将必须包含您自己的副本。
Django 提供了未压缩和“最小化”版本的 jQuery,分别为 jquery.js
和 jquery.min.js
。
ModelAdmin
和 InlineModelAdmin
有一个 media
属性,它返回一个 Media
对象的列表,该列表存储指向表单和/或表单集的 JavaScript 文件的路径。如果 DEBUG
为 True
,它将返回各种 JavaScript 文件的未压缩版本,包括 jquery.js
;如果不是,它将返回“缩小”版本。
向管理中添加自定义验证¶
你还可以向管理中的数据添加自定义验证。自动管理界面会重复使用 django.forms
,而 ModelAdmin
类让你能够定义自己的表单
class ArticleAdmin(admin.ModelAdmin):
form = MyArticleAdminForm
MyArticleAdminForm
可以定义在任何地方,只要在需要的地方导入即可。现在,在你的表单中,你可以为任何字段添加自己的自定义验证
class MyArticleAdminForm(forms.ModelForm):
def clean_name(self):
# do something that validates your data
return self.cleaned_data["name"]
重要的是,你在这里使用 ModelForm
,否则可能会出错。请参阅 表单 文档中的 自定义验证,更具体地说,请参阅 模型表单验证说明 以获取更多信息。
InlineModelAdmin
对象¶
-
class
InlineModelAdmin
¶
-
class
TabularInline
¶
-
class
StackedInline
¶ 管理界面具有在与父模型相同的页面上编辑模型的能力。这些称为内联。假设您有这两个模型
from django.db import models class Author(models.Model): name = models.CharField(max_length=100) class Book(models.Model): author = models.ForeignKey(Author, on_delete=models.CASCADE) title = models.CharField(max_length=100)
您可以在作者页面上编辑由作者编写的书籍。您通过在
ModelAdmin.inlines
中指定内联来将内联添加到模型from django.contrib import admin class BookInline(admin.TabularInline): model = Book class AuthorAdmin(admin.ModelAdmin): inlines = [ BookInline, ]
Django 提供了
InlineModelAdmin
的两个子类,它们是这两个之间的区别仅仅是用于呈现它们的模板。
InlineModelAdmin
选项¶
InlineModelAdmin
共享与 ModelAdmin
相同的许多功能,并添加了一些自己的功能(共享功能实际上是在 BaseModelAdmin
超类中定义的)。共享功能是
form
fieldsets
fields
formfield_overrides
exclude
filter_horizontal
filter_vertical
ordering
prepopulated_fields
get_fieldsets()
get_queryset()
radio_fields
readonly_fields
raw_id_fields
formfield_for_choice_field()
formfield_for_foreignkey()
formfield_for_manytomany()
has_module_permission()
InlineModelAdmin
类添加或自定义
-
InlineModelAdmin.
model
¶ 内联使用的模型。这是必需的。
-
InlineModelAdmin.
fk_name
¶ 模型上的外键名称。在大多数情况下,这将自动处理,但如果存在多个外键指向同一父模型,则必须显式指定
fk_name
。
-
InlineModelAdmin.
formset
¶ 这默认为
BaseInlineFormSet
。使用您自己的表单集可以为您提供许多自定义可能性。内联围绕 模型表单集 构建。
-
InlineModelAdmin.
form
¶
的值默认为form
。这是在创建此内联的表单集时传递给ModelForm
inlineformset_factory()
的内容。
警告
为
表单编写自定义验证时,请谨慎编写依赖于父模型特性的验证。如果父模型未通过验证,则可能会处于不一致的状态,如 ModelForm 上的验证 中的警告所述。InlineModelAdmin
-
InlineModelAdmin.
classes
¶ 包含要应用于为内联呈现的字段集的额外 CSS 类的列表或元组。默认为
。与在None
fieldsets
中配置的类一样,具有
类的内联将最初折叠,其标题将有一个小的“显示”链接。collapse
-
InlineModelAdmin.
extra
¶ 这控制表单集除了初始表单之外将显示的额外表单数量。默认为 3。有关更多信息,请参阅 表单集文档。
对于启用了 JavaScript 的浏览器的用户,提供了一个“添加另一个”链接,以便除了作为
参数的结果提供的内联之外,还可以添加任意数量的附加内联。extra
如果当前显示的表单数量超过
,或者用户未启用 JavaScript,则动态链接将不会出现。max_num
InlineModelAdmin.get_extra()
还允许您自定义额外表单的数量。
-
InlineModelAdmin.
max_num
¶ 这控制了内联中显示的最大表单数。这与对象数没有直接关联,但如果值足够小,则可以关联。有关详细信息,请参阅 限制可编辑对象数。
InlineModelAdmin.get_max_num()
还允许您自定义额外表单的最大数量。
-
InlineModelAdmin.
min_num
¶ 这控制了内联中显示的最小表单数。有关详细信息,请参阅
modelformset_factory()
。InlineModelAdmin.get_min_num()
还允许您自定义显示的最小表单数。
-
InlineModelAdmin.
raw_id_fields
¶ 默认情况下,Django 的管理界面对
ForeignKey
字段使用选择框界面 (<select>)。有时您不希望承担必须选择所有相关实例以在下拉菜单中显示的开销。raw_id_fields
是一个字段列表,您希望将其更改为Input
小组件,用于ForeignKey
或ManyToManyField
class BookInline(admin.TabularInline): model = Book raw_id_fields = ["pages"]
-
InlineModelAdmin.
template
¶ 用于在页面上呈现内联的模板。
-
InlineModelAdmin.
verbose_name
¶ 对模型内部
Meta
类的verbose_name
的覆盖。
-
InlineModelAdmin.
verbose_name_plural
¶ 来自模型内部
Meta
类的verbose_name_plural
的覆盖。如果未给出此项且InlineModelAdmin.verbose_name
已定义,Django 将使用InlineModelAdmin.verbose_name
+'s'
。
-
InlineModelAdmin.
can_delete
¶ 指定是否可以在内联中删除内联对象。默认为
True
。
-
InlineModelAdmin.
show_change_link
¶ 指定是否在管理员中可以更改的内联对象具有指向更改表单的链接。默认为
False
。
-
InlineModelAdmin.
get_formset
(request, obj=None, **kwargs)¶ 返回一个
BaseInlineFormSet
类,用于管理添加/更改视图。obj
是正在编辑的父对象,或在添加新父对象时为None
。有关ModelAdmin.get_formsets_with_inlines
的示例,请参见示例。
-
InlineModelAdmin.
get_extra
(request, obj=None, **kwargs)¶ 返回要使用的额外内联表单的数量。默认情况下,返回
InlineModelAdmin.extra
属性。重写此方法以通过编程方式确定额外内联表单的数量。例如,这可能基于模型实例(作为关键字参数
obj
传递)class BinaryTreeAdmin(admin.TabularInline): model = BinaryTree def get_extra(self, request, obj=None, **kwargs): extra = 2 if obj: return extra - obj.binarytree_set.count() return extra
-
InlineModelAdmin.
get_max_num
(request, obj=None, **kwargs)¶ 返回要使用的最大额外内联表单的数量。默认情况下,返回
InlineModelAdmin.max_num
属性。重写此方法以通过编程方式确定最大内联表单的数量。例如,这可能基于模型实例(作为关键字参数
obj
传递)class BinaryTreeAdmin(admin.TabularInline): model = BinaryTree def get_max_num(self, request, obj=None, **kwargs): max_num = 10 if obj and obj.parent: return max_num - 5 return max_num
-
InlineModelAdmin.
get_min_num
(request, obj=None, **kwargs)¶ 返回要使用的最小内联表单的数量。默认情况下,返回
InlineModelAdmin.min_num
属性。覆盖此方法以以编程方式确定内联表单的最小数量。例如,这可能基于模型实例(作为关键字参数
obj
传递)。
-
InlineModelAdmin.
has_add_permission
(request, obj)¶ 如果允许添加内联对象,则应返回
True
,否则返回False
。obj
是正在编辑的父对象,或在添加新父对象时为None
。
-
InlineModelAdmin.
has_change_permission
(request, obj=None)¶ 如果允许编辑内联对象,则应返回
True
,否则返回False
。obj
是正在编辑的父对象。
-
InlineModelAdmin.
has_delete_permission
(request, obj=None)¶ 如果允许删除内联对象,则应返回
True
,否则返回False
。obj
是正在编辑的父对象。
注意
传递给 InlineModelAdmin
方法的 obj
参数是正在编辑的父对象,或在添加新父对象时为 None
。
使用具有两个或更多外键指向同一父模型的模型¶
有时可能有多个外键指向同一模型。以这个模型为例
from django.db import models
class Friendship(models.Model):
to_person = models.ForeignKey(
Person, on_delete=models.CASCADE, related_name="friends"
)
from_person = models.ForeignKey(
Person, on_delete=models.CASCADE, related_name="from_friends"
)
如果您想在 Person
管理添加/更改页面上显示内联,则需要明确定义外键,因为它无法自动执行此操作
from django.contrib import admin
from myapp.models import Friendship
class FriendshipInline(admin.TabularInline):
model = Friendship
fk_name = "to_person"
class PersonAdmin(admin.ModelAdmin):
inlines = [
FriendshipInline,
]
使用多对多模型¶
默认情况下,多对多关系的管理小部件将显示在包含 ManyToManyField
实际引用的任何模型上。根据您的 ModelAdmin
定义,模型中的每个多对多字段将由标准 HTML <select multiple>
、水平或垂直筛选器或 raw_id_fields
小部件表示。但是,也可以用内联替换这些小部件。
假设我们有以下模型
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, related_name="groups")
如果您想使用内联显示多对多关系,可以通过为该关系定义 InlineModelAdmin
对象来实现
from django.contrib import admin
class MembershipInline(admin.TabularInline):
model = Group.members.through
class PersonAdmin(admin.ModelAdmin):
inlines = [
MembershipInline,
]
class GroupAdmin(admin.ModelAdmin):
inlines = [
MembershipInline,
]
exclude = ["members"]
此示例中有两个值得注意的功能。
首先 - MembershipInline
类引用 Group.members.through
。 through
属性是对管理多对多关系的模型的引用。当您定义多对多字段时,Django 会自动创建此模型。
其次,GroupAdmin
必须手动排除 members
字段。Django 在定义关系的模型(在本例中为 Group
)上显示多对多字段的管理小组件。如果您想使用内联模型来表示多对多关系,则必须告知 Django 的管理小组件不显示此小组件 - 否则您最终将在管理页面上看到两个用于管理关系的小组件。
请注意,当使用此技术时,m2m_changed
信号不会被触发。这是因为,就管理小组件而言,through
只是一个具有两个外键字段的模型,而不是多对多关系。
在所有其他方面,InlineModelAdmin
与其他任何模型完全相同。您可以使用任何常规 ModelAdmin
属性自定义外观。
使用多对多中间模型¶
当您使用 through
参数将中间模型指定给 ManyToManyField
时,管理小组件默认不会显示小组件。这是因为该中间模型的每个实例都需要的信息比单个小组件中显示的信息更多,并且多个小组件所需的布局会根据中间模型而有所不同。
但是,我们仍然希望能够内联编辑该信息。幸运的是,我们可以使用内联管理模型来实现此目的。假设我们有以下模型
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=128)
class Group(models.Model):
name = models.CharField(max_length=128)
members = models.ManyToManyField(Person, through="Membership")
class Membership(models.Model):
person = models.ForeignKey(Person, on_delete=models.CASCADE)
group = models.ForeignKey(Group, on_delete=models.CASCADE)
date_joined = models.DateField()
invite_reason = models.CharField(max_length=64)
在管理小组件中显示此中间模型的第一步是为 Membership
模型定义一个内联类
class MembershipInline(admin.TabularInline):
model = Membership
extra = 1
此示例使用 Membership
模式的默认 InlineModelAdmin
值,并将额外的添加表单限制为一个。这可以使用 InlineModelAdmin
类可用的任何选项进行自定义。
现在为 Person
和 Group
模式创建管理视图
class PersonAdmin(admin.ModelAdmin):
inlines = [MembershipInline]
class GroupAdmin(admin.ModelAdmin):
inlines = [MembershipInline]
最后,使用管理站点注册 Person
和 Group
模式
admin.site.register(Person, PersonAdmin)
admin.site.register(Group, GroupAdmin)
现在,您的管理站点已设置为从 Person
或 Group
详细信息页面内联编辑 Membership
对象。
将泛型关系用作内联¶
可以使用内联与泛型相关对象。假设您有以下模式
from django.contrib.contenttypes.fields import GenericForeignKey
from django.db import models
class Image(models.Model):
image = models.ImageField(upload_to="images")
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey("content_type", "object_id")
class Product(models.Model):
name = models.CharField(max_length=100)
如果您想允许在 Product
的添加/更改视图中编辑和创建 Image
实例,可以使用 GenericTabularInline
或 GenericStackedInline
(GenericInlineModelAdmin
的两个子类),由 admin
提供。它们分别为表示内联对象的表单实现表格和堆叠的可视化布局,就像它们的非泛型对应项一样。它们的行为与任何其他内联一样。在此示例应用程序的 admin.py
中
from django.contrib import admin
from django.contrib.contenttypes.admin import GenericTabularInline
from myapp.models import Image, Product
class ImageInline(GenericTabularInline):
model = Image
class ProductAdmin(admin.ModelAdmin):
inlines = [
ImageInline,
]
admin.site.register(Product, ProductAdmin)
有关更具体的信息,请参阅 contenttypes 文档。
覆盖管理模板¶
您可以覆盖管理模块用于生成管理站点各个页面的许多模板。您甚至可以为特定应用程序或特定模式覆盖其中一些模板。
设置项目的管理模板目录¶
管理模板文件位于 django/contrib/admin/templates/admin 目录中。
为了覆盖其中一个或多个,首先在项目的 templates
目录中创建一个 admin
目录。这可以是你 DIRS
选项中指定的 DjangoTemplates
后端的 TEMPLATES
设置中的任何目录。如果你自定义了 'loaders'
选项,请确保 'django.template.loaders.filesystem.Loader'
出现在 'django.template.loaders.app_directories.Loader'
之前,以便模板加载系统在 django.contrib.admin
中包含的模板之前找到你的自定义模板。
在此 admin
目录中,创建以你的应用命名的子目录。在这些应用子目录中,创建以你的模型命名的子目录。请注意,admin 应用在查找目录时会将模型名称小写,因此如果你要在区分大小写的文件系统上运行你的应用,请确保将目录名称全部小写。
要覆盖特定应用的管理模板,请从 django/contrib/admin/templates/admin 目录复制并编辑模板,然后将其保存到你刚创建的其中一个目录中。
例如,如果我们想为名为 my_app
的应用中的所有模型添加一个工具到更改列表视图,我们将 contrib/admin/templates/admin/change_list.html
复制到我们项目的 templates/admin/my_app/
目录,并进行任何必要的更改。
如果我们想为仅名为“页面”的特定模型添加一个工具到更改列表视图,我们将把该文件复制到我们项目的 templates/admin/my_app/page
目录。
重写与替换管理模板¶
由于管理模板的模块化设计,通常既没有必要也没有建议替换整个模板。几乎总是最好只重写模板中需要更改的部分。
继续上面的示例,我们希望在 Page
模型的 History
工具旁边添加一个新链接。在查看 change_form.html
后,我们确定只需要重写 object-tools-items
块。因此,以下是我们新的 change_form.html
{% extends "admin/change_form.html" %}
{% load i18n admin_urls %}
{% block object-tools-items %}
<li>
<a href="{% url opts|admin_urlname:'history' original.pk|admin_urlquote %}" class="historylink">{% translate "History" %}</a>
</li>
<li>
<a href="mylink/" class="historylink">My Link</a>
</li>
{% if has_absolute_url %}
<li>
<a href="{% url 'admin:view_on_site' content_type_id original.pk %}" class="viewsitelink">{% translate "View on site" %}</a>
</li>
{% endif %}
{% endblock %}
就是这样!如果我们将此文件放在 templates/admin/my_app
目录中,我们的链接将出现在 my_app 中所有模型的更改表单上。
可以按应用或模型重写的模板¶
并非 contrib/admin/templates/admin
中的每个模板都可以按应用或按模型重写。以下可以
actions.html
app_index.html
change_form.html
change_form_object_tools.html
change_list.html
change_list_object_tools.html
change_list_results.html
date_hierarchy.html
delete_confirmation.html
object_history.html
pagination.html
popup_response.html
prepopulated_fields_js.html
search_form.html
submit_line.html
对于无法以这种方式重写的那些模板,你仍然可以通过将新版本放在 templates/admin
目录中,为整个项目重写它们。这对于创建自定义 404 和 500 页面特别有用。
注意
一些管理模板,例如 change_list_results.html
,用于呈现自定义包含标签。这些可以被重写,但在这种情况下,你最好创建自己的版本,并给它一个不同的名称。这样你就可以有选择地使用它。
根和登录模板¶
如果您希望更改索引、登录或注销模板,最好创建自己的 AdminSite
实例(见下文),并更改 AdminSite.index_template
、AdminSite.login_template
或 AdminSite.logout_template
属性。
主题支持¶
管理员使用 CSS 变量定义颜色和字体。这样可以更改主题,而无需覆盖许多单独的 CSS 规则。例如,如果您更喜欢紫色而不是蓝色,可以向项目添加 admin/base.html
模板覆盖
{% extends 'admin/base.html' %}
{% block extrastyle %}{{ block.super }}
<style>
html[data-theme="light"], :root {
--primary: #9774d5;
--secondary: #785cab;
--link-fg: #7c449b;
--link-selected-fg: #8f5bb2;
}
</style>
{% endblock %}
CSS 变量列表定义在 django/contrib/admin/static/admin/css/base.css。
尊重 prefers-color-scheme 媒体查询的暗模式变量定义在 django/contrib/admin/static/admin/css/dark_mode.css。这链接到 {% block dark-mode-vars %}
中的文档。
AdminSite
对象¶
-
class
AdminSite
(name='admin')¶ Django 管理站点由
django.contrib.admin.sites.AdminSite
的实例表示;默认情况下,此类的实例创建为django.contrib.admin.site
,您可以在其中注册您的模型和ModelAdmin
实例。如果您想自定义默认管理站点,可以 覆盖它。
在构建
AdminSite
实例时,可以使用name
参数向构造函数提供一个唯一的实例名称。此实例名称用于标识实例,尤其是在 反转管理 URL 时。如果没有提供实例名称,将使用默认实例名称admin
。有关自定义 AdminSite 类 的示例,请参阅AdminSite
类的自定义。
AdminSite
属性¶
模板可以覆盖或扩展基本管理模板,如 覆盖管理模板 中所述。
-
AdminSite.
site_header
¶ 作为
<div>
(一个字符串)放置在每个管理页面顶部的文本。默认情况下,这是“Django 管理”。在 Django 5.0 中更改在较早的版本中,
site_header
使用<h1>
标记。
-
AdminSite.
site_title
¶ 放置在每个管理页面的
<title>
末尾的文本(一个字符串)。默认情况下,这是“Django 站点管理”。
-
AdminSite.
site_url
¶ 每个管理页面顶部“查看站点”链接的 URL。默认情况下,
site_url
为/
。将其设置为None
以删除链接。对于在子路径上运行的站点,
each_context()
方法检查当前请求是否设置了request.META['SCRIPT_NAME']
,如果site_url
未设置为除/
之外的其他值,则使用该值。
-
AdminSite.
index_title
¶ 放置在管理索引页面顶部的文本(一个字符串)。默认情况下,这是“站点管理”。
-
AdminSite.
index_template
¶ 将由管理站点主索引视图使用的自定义模板的路径。
-
AdminSite.
app_index_template
¶ 将由管理站点应用索引视图使用的自定义模板的路径。
-
AdminSite.
empty_value_display
¶ 用于在管理站点的更改列表中显示空值的字符串。默认为破折号。还可以在每个
ModelAdmin
的基础上以及ModelAdmin
中的自定义字段中覆盖该值,方法是在字段上设置empty_value_display
属性。有关示例,请参见ModelAdmin.empty_value_display
。
一个布尔值,用于确定在较大的屏幕上是否显示导航侧边栏。默认情况下,它设置为
True
。
-
AdminSite.
final_catch_all_view
¶ 一个布尔值,用于确定是否向管理员添加最终的 catch-all 视图,该视图将未经身份验证的用户重定向到登录页面。默认情况下,它设置为
True
。警告
不建议将此值设置为
False
,因为该视图可以防止潜在的模型枚举隐私问题。
-
AdminSite.
login_template
¶ 自定义模板的路径,该模板将由管理员网站登录视图使用。
-
AdminSite.
login_form
¶ AuthenticationForm
的子类,该子类将由管理员网站登录视图使用。
-
AdminSite.
logout_template
¶ 自定义模板的路径,该模板将由管理员网站注销视图使用。
-
AdminSite.
password_change_template
¶ 自定义模板的路径,该模板将由管理员网站密码更改视图使用。
-
AdminSite.
password_change_done_template
¶ 自定义模板的路径,该模板将由管理员网站密码更改完成视图使用。
AdminSite
方法¶
-
AdminSite.
each_context
(request)¶ 返回一个变量字典,用于放置在管理站点中每个页面的模板上下文中。
默认情况下包括以下变量和值
site_header
:AdminSite.site_header
site_title
:AdminSite.site_title
site_url
:AdminSite.site_url
has_permission
:AdminSite.has_permission()
available_apps
: 应用程序注册表 中的应用程序列表,可供当前用户使用。列表中的每个条目都是一个表示应用程序的字典,其中包含以下键app_label
: 应用程序标签app_url
: 管理中应用程序索引的 URLhas_module_perms
: 一个布尔值,表示当前用户是否允许显示和访问模块的索引页models
: 应用程序中可用的模型列表
每个模型都是一个具有以下键的字典
model
:模型类object_name
:模型的类名name
:模型的复数名称perms
:一个dict
,用于跟踪add
、change
、delete
和view
权限admin_url
:模型的管理变更列表 URLadd_url
:添加新模型实例的管理 URL
is_popup
:当前页面是否显示在弹出窗口中is_nav_sidebar_enabled
:AdminSite.enable_nav_sidebar
log_entries
:AdminSite.get_log_entries()
-
AdminSite.
get_app_list
(request, app_label=None)¶ 从 应用程序注册表 返回当前用户可用的应用程序列表。你可以选择传递一个
app_label
参数来获取单个应用程序的详细信息。列表中的每个条目都是一个表示应用程序的字典,具有以下键app_label
: 应用程序标签app_url
: 管理中应用程序索引的 URLhas_module_perms
: 一个布尔值,表示当前用户是否允许显示和访问模块的索引页models
: 应用程序中可用的模型列表name
:应用程序的名称
每个模型都是一个具有以下键的字典
model
:模型类object_name
:模型的类名name
:模型的复数名称perms
:一个dict
,用于跟踪add
、change
、delete
和view
权限admin_url
:模型的管理变更列表 URLadd_url
:添加新模型实例的管理 URL
应用程序和模型的列表按名称按字母顺序排列。你可以在管理索引页面上覆盖此方法以更改默认顺序。
-
AdminSite.
has_permission
(request)¶ 如果给定
HttpRequest
的用户有权查看管理网站中的至少一页,则返回True
。默认情况下,要求User.is_active
和User.is_staff
均为True
。
-
AdminSite.
register
(model_or_iterable, admin_class=None, **options)¶ 使用给定的
admin_class
注册给定的模型类(或类的可迭代对象)。admin_class
默认为ModelAdmin
(默认的管理选项)。如果给出了关键字参数(例如list_display
),它们将作为选项应用于管理类。如果模型是抽象的,则引发
ImproperlyConfigured
;如果模型已注册,则引发django.contrib.admin.exceptions.AlreadyRegistered
。
-
AdminSite.
unregister
(model_or_iterable)¶ 取消注册给定的模型类(或类的可迭代对象)。
如果模型尚未注册,则引发
django.contrib.admin.exceptions.NotRegistered
。
-
AdminSite.
get_model_admin
(model)¶ - Django 5.0 中的新增功能。
返回给定模型类的管理类。如果模型未注册,则引发
django.contrib.admin.exceptions.NotRegistered
。
将 AdminSite
实例挂接到你的 URLconf¶
设置 Django 管理的最后一步是将你的 AdminSite
实例挂接到你的 URLconf。通过将给定的 URL 指向 AdminSite.urls
方法来实现。没有必要使用 include()
。
在此示例中,我们在 URL /admin/
处注册了默认 AdminSite
实例 django.contrib.admin.site
# urls.py
from django.contrib import admin
from django.urls import path
urlpatterns = [
path("admin/", admin.site.urls),
]
自定义 AdminSite
类¶
如果你希望使用自定义行为设置自己的管理网站,你可以随意地对 AdminSite
进行子类化,并覆盖或添加任何你喜欢的功能。然后,创建一个 AdminSite
子类的实例(以你实例化任何其他 Python 类的相同方式),并使用它来注册你的模型和 ModelAdmin
子类,而不是使用默认网站。最后,更新 myproject/urls.py
以引用你的 AdminSite
子类。
from django.contrib import admin
from .models import MyModel
class MyAdminSite(admin.AdminSite):
site_header = "Monty Python administration"
admin_site = MyAdminSite(name="myadmin")
admin_site.register(MyModel)
from django.urls import path
from myapp.admin import admin_site
urlpatterns = [
path("myadmin/", admin_site.urls),
]
请注意,在使用您自己的 AdminSite
实例时,您可能不希望自动发现 admin
模块,因为您很可能在 myproject.admin
模块中导入所有按应用划分的 admin
模块。这意味着您需要在 INSTALLED_APPS
设置中将 'django.contrib.admin.apps.SimpleAdminConfig'
放在 'django.contrib.admin'
的位置。
覆盖默认管理站点¶
您可以通过将自定义 AppConfig
的 default_site
属性设置为 AdminSite
子类的点导入路径或返回站点实例的可调用对象,来覆盖默认的 django.contrib.admin.site
。
from django.contrib import admin
class MyAdminSite(admin.AdminSite): ...
from django.contrib.admin.apps import AdminConfig
class MyAdminConfig(AdminConfig):
default_site = "myproject.admin.MyAdminSite"
INSTALLED_APPS = [
# ...
"myproject.apps.MyAdminConfig", # replaces 'django.contrib.admin'
# ...
]
在同一 URLconf 中有多个管理站点¶
您可以在同一 Django 支持的网站上创建管理站点的多个实例。创建 AdminSite
的多个实例,并将每个实例放在不同的 URL 中。
在此示例中,URL /basic-admin/
和 /advanced-admin/
分别使用 AdminSite
实例 myproject.admin.basic_site
和 myproject.admin.advanced_site
提供管理站点的不同版本。
# urls.py
from django.urls import path
from myproject.admin import advanced_site, basic_site
urlpatterns = [
path("basic-admin/", basic_site.urls),
path("advanced-admin/", advanced_site.urls),
]
AdminSite
实例采用其构造函数的单个参数,即其名称,可以是您喜欢的任何名称。此参数将成为 URL 名称的前缀,以便 反转它们。仅当您使用多个 AdminSite
时才需要这样做。
向管理站点添加视图¶
就像 ModelAdmin
一样,AdminSite
提供了一个 get_urls()
方法,可以覆盖该方法以定义站点的其他视图。要向你的管理站点添加一个新视图,请扩展基本 get_urls()
方法,以包含新视图的模式。
注意
你呈现的任何使用管理模板或扩展基本管理模板的视图,都应在呈现模板之前设置 request.current_app
。如果你的视图位于 AdminSite
上,则应将其设置为 self.name
,如果你的视图位于 ModelAdmin
上,则应将其设置为 self.admin_site.name
。
添加密码重置功能¶
你可以通过向你的 URLconf 添加几行来向管理站点添加密码重置功能。具体来说,添加这四个模式
from django.contrib import admin
from django.contrib.auth import views as auth_views
path(
"admin/password_reset/",
auth_views.PasswordResetView.as_view(
extra_context={"site_header": admin.site.site_header}
),
name="admin_password_reset",
),
path(
"admin/password_reset/done/",
auth_views.PasswordResetDoneView.as_view(
extra_context={"site_header": admin.site.site_header}
),
name="password_reset_done",
),
path(
"reset/<uidb64>/<token>/",
auth_views.PasswordResetConfirmView.as_view(
extra_context={"site_header": admin.site.site_header}
),
name="password_reset_confirm",
),
path(
"reset/done/",
auth_views.PasswordResetCompleteView.as_view(
extra_context={"site_header": admin.site.site_header}
),
name="password_reset_complete",
),
(这假设你在 admin/
中添加了管理,并且要求你在包含管理应用程序本身的那一行之前放置以 ^admin/
开头的 URL)。
命名 URL admin_password_reset
的存在将导致在密码框下方的默认管理登录页面上出现“忘记密码?”链接。
LogEntry
对象¶
-
class
models.
LogEntry
¶ LogEntry
类跟踪通过管理界面完成的对象的添加、更改和删除。
LogEntry
属性¶
-
LogEntry.
action_time
¶ 操作的日期和时间。
-
LogEntry.
user
¶ 执行操作的用户(
AUTH_USER_MODEL
实例)。
-
LogEntry.
content_type
¶ 修改对象的
ContentType
。
-
LogEntry.
object_id
¶ 修改对象的文本表示形式的主键。
-
LogEntry.
object_repr
¶ 修改后的对象的
repr()
。
-
LogEntry.
action_flag
¶ 记录的操作类型:
ADDITION
、CHANGE
、DELETION
。例如,要获取通过管理员完成的所有添加操作的列表
from django.contrib.admin.models import ADDITION, LogEntry LogEntry.objects.filter(action_flag=ADDITION)
-
LogEntry.
change_message
¶ 修改的详细说明。例如,在编辑的情况下,消息包含已编辑字段的列表。Django 管理员站点将此内容格式化为 JSON 结构,以便
get_change_message()
可以重新组合以当前用户语言翻译的消息。不过,自定义代码可能会将其设置为纯字符串。建议您使用get_change_message()
方法来检索此值,而不是直接访问它。
LogEntry
方法¶
-
LogEntry.
get_edited_object
()¶ 返回引用的对象的快捷方式。
-
LogEntry.
get_change_message
()¶ 格式化并翻译
change_message
为当前用户语言。在 Django 1.10 之前创建的消息将始终以记录时的语言显示。
反转管理 URL¶
部署 AdminSite
时,可以使用 Django 的 URL 反转系统 访问该站点提供的视图。
AdminSite
提供以下命名 URL 模式
页面 | URL 名称 | 参数 |
---|---|---|
索引 | index |
|
登录 | login |
|
注销 | logout |
|
更改密码 | password_change |
|
密码更改完成 | password_change_done |
|
i18n JavaScript | jsi18n |
|
应用程序索引页面 | app_list |
app_label |
重定向到对象的页面 | view_on_site |
content_type_id , object_id |
每个 ModelAdmin
实例提供一组额外的命名 URL
页面 | URL 名称 | 参数 |
---|---|---|
变更列表 | {{ app_label }}_{{ model_name }}_changelist |
|
添加 | {{ app_label }}_{{ model_name }}_add |
|
历史记录 | {{ app_label }}_{{ model_name }}_history |
object_id |
删除 | {{ app_label }}_{{ model_name }}_delete |
object_id |
更改 | {{ app_label }}_{{ model_name }}_change |
object_id |
UserAdmin
提供一个命名 URL
页面 | URL 名称 | 参数 |
---|---|---|
更改密码 | auth_user_password_change |
user_id |
这些命名 URL 已在应用程序命名空间 admin
中注册,并在与站点实例名称相对应的实例命名空间中注册。
因此 - 如果你想获取默认管理中的特定 Choice
对象(来自 polls 应用程序)的更改视图的引用,则可以调用
>>> from django.urls import reverse
>>> c = Choice.objects.get(...)
>>> change_url = reverse("admin:polls_choice_change", args=(c.id,))
这将找到管理应用程序的第一个已注册实例(无论实例名称是什么),并解析为在该实例中更改 poll.Choice
实例的视图。
如果你想在特定管理实例中找到 URL,请将该实例的名称作为 current_app
提示提供给反向调用。例如,如果你特别想要名为 custom
的管理实例中的管理视图,则需要调用
>>> change_url = reverse("admin:polls_choice_change", args=(c.id,), current_app="custom")
有关更多详细信息,请参阅 反转命名空间 URL 中的文档。
为了更容易地反转模板中的管理 URL,Django 提供了一个 admin_urlname
过滤器,它将操作作为参数
{% load admin_urls %}
<a href="{% url opts|admin_urlname:'add' %}">Add user</a>
<a href="{% url opts|admin_urlname:'delete' user.pk %}">Delete this user</a>
上面示例中的操作与上面描述的 ModelAdmin
实例的 URL 名称的最后部分匹配。 opts
变量可以是具有 app_label
和 model_name
属性的任何对象,并且通常由当前模型的管理视图提供。
display
装饰器¶
-
display
(*, boolean=None, ordering=None, description=None, empty_value=None)¶ 此装饰器可用于为自定义显示函数设置特定属性,这些属性可与
list_display
或readonly_fields
一起使用@admin.display( boolean=True, ordering="-publish_date", description="Is Published?", ) def is_published(self, obj): return obj.publish_date is not None
这等同于直接在函数上设置某些属性(使用原始的、较长的名称)
def is_published(self, obj): return obj.publish_date is not None is_published.boolean = True is_published.admin_order_field = "-publish_date" is_published.short_description = "Is Published?"
另请注意,
empty_value
装饰器参数映射到直接分配给函数的empty_value_display
属性。它不能与boolean
结合使用,它们是互斥的。使用此装饰器并不是创建显示函数的强制要求,但将其用作源代码中的标记来标识函数的目的可能很有用,而无需参数
@admin.display def published_year(self, obj): return obj.publish_date.year
在这种情况下,它不会向函数添加任何属性。
staff_member_required
装饰器¶
-
staff_member_required
(redirect_field_name='next', login_url='admin:login')¶ 此装饰器用于需要授权的管理视图。使用此函数装饰的视图将具有以下行为
- 如果用户已登录,是工作人员(
User.is_staff=True
),并且处于活动状态(User.is_active=True
),则正常执行视图。 - 否则,请求将被重定向到由
login_url
参数指定的 URL,其中原始请求的路径在由redirect_field_name
指定的查询字符串变量中。例如:/admin/login/?next=/admin/polls/question/3/
。
示例用法
from django.contrib.admin.views.decorators import staff_member_required @staff_member_required def my_view(request): ...
- 如果用户已登录,是工作人员(