Django 管理站点
Django 管理站点
Django 最强大的部分之一是自动管理界面。它从你的模型中读取元数据,提供一个快速的、以模型为中心的界面,受信任的用户可以管理你网站上的内容。管理的推荐使用范围仅限于一个组织的内部管理工具。它不打算用于围绕你的整个前端构建。
管理有很多用于定制的钩子,但要注意不要试图专门使用这些钩子。如果你需要提供一个更以流程为中心的接口,抽象掉数据库表和字段的实现细节,那么可能是时候编写自己的视图了。
在本文档中,我们将讨论如何激活、使用和定制 Django 的管理界面。
概况
在 startproject 使用的默认项目模板中启用了管理。
如果你没有使用默认的项目模板,这里是要求:
- 将
'django.contrib.admin'和它的依赖关系 —— django.contrib.auth、django.contrib.contenttypes、django.contrib.messages 和django.contrib.session添加到你的 INSTALLED_APPS 配置中。 - 在你的 TEMPLATES 配置中设置一个在 OPTIONS 的
'context_processors'选项中包含django.template.context_processors.request、django.contrib.auth.context_processors.auth和django.contrib.messages.context_processors.messages的 DjangoTemplates 后端: - If you’ve customized the MIDDLEWARE setting, django.contrib.sessions.middleware.SessionMiddleware, django.contrib.auth.middleware.AuthenticationMiddleware, and django.contrib.messages.middleware.MessageMiddleware must be included.
- 把管理的网址挂到你的 URLconf 里。
在你采取了这些步骤之后,你就可以通过访问你挂接的 URL(默认是 /admin/)来使用管理站点。
如果需要创建一个用户来登录,请使用 createsuperuser 命令。默认情况下,登录管理需要用户的 is_staff 属性设置为 True。
最后,确定你的应用程序的哪些模型应该在管理界面中是可编辑的。对于这些模型中的每一个,按照 ModelAdmin 中的描述,在管理处注册它们。
其他主题
参见
关于在生产中服务与管理相关的静态文件(图像、JavaScript 和 CSS)的信息,请参见 提供文件服务。
有问题? 试试 FAQ:管理。
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()。
default_site
一个点分隔的导入路径,用于导入默认的管理站点类,或者导入一个返回站点实例的可调用类。默认为 'django.contrib.admin.sites.AdminSite'。使用方法参见 覆盖默认的管理站点。
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
要在变更列表页上提供的动作列表。详见 管理动作。
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)
如果你想让 Author 模型的表格只包括 name 和 title 字段,你可以指定 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 中定义的值,以只读方式显示。
对于更复杂的布局需求,请参阅 fieldets 选项。
The fields option accepts the same types of values as list_display, except that callables and __ lookups for related fields aren’t accepted. Names of model and model admin methods will only be used if they’re listed in 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> 是表单的一个 “section”)。
这些 2-元组的格式是 (name, field_options),其中 name 是表示 fieldset 标题的字符串,而 field_options 是关于 fieldset 的信息的字典,包括要在其中显示的字段列表。
一个完整的例子,取自 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
A list or tuple containing extra CSS classes to apply to the fieldset. This can include any custom CSS class defined in the project, as well as any of the CSS classes provided by Django. Within the default admin site CSS stylesheet, two particularly useful classes are defined: collapse and wide.
举例:
{
"classes": ["wide", "collapse"],
}
Fieldsets with the wide style will be given extra horizontal space in the admin interface. Fieldsets with a name and the collapse style will be initially collapsed, using an expandable widget with a toggle for switching their visibility.
Changed in Django 5.1:
fieldsets using the collapse class now use <details> and <summary> elements, provided they define a name.
description
A string of optional extra text to be displayed at the top of each fieldset, under the heading of the fieldset.
请注意,当这个值在管理界面显示时,它不是 HTML 转义后的 。如果你愿意的话,这可以让你包含 HTML。或者你可以使用纯文本和 django.utils.html.escape() 来转义任何 HTML 特殊字符。
TabularInline has limited support for fieldsets
Using fieldsets with TabularInline has limited functionality. You can specify which fields will be displayed and their order within the TabularInline layout by defining fields in the field_options dictionary.
All other features are not supported. This includes the use of name to define a title for a group of fields.
ModelAdmin.filter_horizontal
默认情况下,在管理网站中显示一个 ManyToManyField 是 <select multiple>。但是,多选框在选择很多项目时,会很难用。在这个列表中添加一个 ManyToManyField,就可以改用一个不显眼的 JavaScript “过滤器” 界面,在选项中进行搜索。未选择和选择的选项并排出现在两个框中。参见 filter_vertical 来使用垂直界面。
ModelAdmin.filter_vertical
与 filter_horizontal 相同,但使用垂直显示过滤界面,未选择的选项框出现在选择选项框的上方。
ModelAdmin.form
默认情况下,会为你的模型动态创建一个 ModelForm。它用于创建在添加/更改页面上显示的表单。你可以很容易地提供你自己的 ModelForm 来覆盖添加/更改页面上的任何默认表单行为。另外,你可以使用 ModelAdmin.get_form() 方法来定制默认的表单,而不是指定一个全新的表单。
示例请参见 在管理中添加自定义验证 一节。
省略 Meta.model 属性
如果你在 ModelForm 上定义了 Meta.model 属性,你也必须定义 Meta.fields 属性(或 Meta.exclude 属性)。但是,由于管理有自己定义字段的方式,所以 Meta.field 属性将被忽略。
如果 ModelForm 只用于管理,最简单的解决办法是省略 Meta.model 属性,因为 ModelAdmin 将提供正确的模型。或者,你可以在 Meta 类中设置 fields = [] 以满足 ModelForm 的验证。
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
在上面的例子中,“年龄” 字段将被排除,但 “姓名” 字段将被包含在生成的表单中。
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__() 表示。
There are five types of values that can be used in list_display. All but the simplest may use the display() decorator, which is used to customize how the field is presented:
- 模型字段的名称。例如:
class PersonAdmin(admin.ModelAdmin):
list_display = ["first_name", "last_name"]
- The name of a related field, using the
__notation. For example:
class PersonAdmin(admin.ModelAdmin):
list_display = ["city__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"]
Changed in Django 5.1:
Support for using __ lookups was added, when targeting related fields.
关于 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` :
``` 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"]
__str__()方法在list_display中和其他模型方法一样有效,所以完全可以这样做:
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 相关的属性,而不是使用 [display()](#django.contrib.admin.display "django.contrib.admin.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)
Changed in Django 5.0:
支持在属性上使用 `boolean` 属性已经添加。
-
list_display中的字段名也会以 CSS 类的形式出现在 HTML 输出中,在每个<th>元素上以column-<field_name>的形式出现。例如,这可以用来在 CSS 文件中设置列宽。 -
Django 会尝试按照这个顺序解释
list_display的每个元素:- A field of the model or from a related field.
- 一个可调用对象。
- 一个代表
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 以在管理员的更改列表页面右侧边栏上激活过滤器。
在最简单的情况下,list_filter 接受一个字段名称的列表或元组以激活过滤,但还有更多高级选项可供选择。详细信息请参阅 ModelAdmin 列表过滤器。
ModelAdmin.list_max_show_all
设置 list_max_show_all 来控制 “全部显示” 的管理员更改列表页面上可以出现多少个项目。只有当总结果数小于或等于此配置时,管理才会在更改列表中显示 “全部显示” 链接。默认情况下,这个配置为 200。
ModelAdmin.list_per_page
设置 list_per_page 来控制每个分页的管理变更列表页面上出现多少个项目。默认情况下,设置为 100。
ModelAdmin.list_select_related
设置 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() 方法。
备注
当 select_related() 已经在变更列表的 QuerySet 上被调用时,ModelAdmin 会忽略这个属性。
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
New in Django 5.0.
控制是否在管理列表中显示筛选器的 facet 计数。默认值为 ShowFacets.ALLOW。
当显示时,facet 计数会根据当前应用的筛选器而更新。
- class
ShowFacets
New in Django 5.0.
对于 ModelAdmin.show_facets 的允许值的枚举。
* `ALWAYS`
始终显示 facet 计数。
* `ALLOW`
当提供 _facets 查询字符串参数时显示 facet 计数。
* `NEVER`
从不显示 facet 计数。
将 show_facets 设置为所需的 ShowFacets 值。例如,要始终显示 facet 计数而无需提供查询参数:
from django.contrib import admin
class MyModelAdmin(admin.ModelAdmin):
...
# Have facets always shown for this model admin.
show_facets = admin.ShowFacets.ALWAYS
性能考虑与 facets
启用 facet 过滤器将增加与筛选器数量相匹配的管理列表页面上的查询数量。这些查询可能会引发性能问题,特别是对于大型数据集。在这些情况下,将 show_facets 设置为 ShowFacets.NEVER 可以完全禁用 faceting。
ModelAdmin.radio_fields
默认情况下,Django 的管理对于 ForeignKey 或设置了 choices 的字段使用选择框界面(<select>)。如果字段存在于 radio_fields 中,Django 将使用单选按钮接口代替。假设 group 是 Person 模型上的一个 ForeignKey :
class PersonAdmin(admin.ModelAdmin):
radio_fields = {"group": admin.VERTICAL}
你可以在 django.contrib.admin 模块中选择使用 HORIZONTAL 或 VERTICAL。
不要在 radio_fields 中包含一个字段,除非它是 ForeignKey 或已设置 choices。
ModelAdmin.autocomplete_fields
autocomplete_fields 是一个 ForeignKey 和/或 ManyToManyField 字段的列表,你想将其改为 Select2 自动完成输入。
autocomplete_fields 是一个 ForeignKey 和/或的列表,默认情况下,管理对这些字段使用选择框接口(<select>)。有时你不想产生选择所有相关实例在下拉中显示的开销。ManyToManyField 字段你想改成 Select2 自动完成输入。
Select2 输入看起来与默认输入类似,但自带搜索功能,异步加载选项。如果相关模型有很多实例,这样会更快、更方便用户使用。
你必须在相关对象的 ModelAdmin 上定义 search_fields,因为自动完成搜索使用它。
为了避免未经授权的数据泄露,用户必须拥有相关对象的 view 或 change 权限才能使用自动完成。
结果的排序和分页由相关的 ModelAdmin 的 get_ordering() 和 get_paginator() 方法控制。
在下面的例子中,ChoiceAdmin 对 Question 有一个 ForeignKey 的自动完成字段。结果由 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 是你想改变为 ForeignKey 或 ManyToManyField 的 Input 部件的字段列表:
class ArticleAdmin(admin.ModelAdmin):
raw_id_fields = ["newspaper"]
raw_id_fields 的 Input 部件应该包含一个主键,如果该字段是 `ForeignKey 。或者是一个逗号分隔的值列表,如果该字段是ManyToManyField。raw_id_fields` 部件在字段旁边显示一个放大镜按钮,允许用户搜索和选择一个值:
ModelAdmin.readonly_fields
默认情况下,管理会将所有字段显示为可编辑。该选项中的任何字段(应该是 list 或 tuple)将按原样显示其数据,不可编辑;它们也被排除在用于创建和编辑的 ModelForm 中。请注意,当指定 ModelAdmin.fields 或 ModelAdmin.fieldsets 时,只读字段必须存在才能显示(否则将被忽略)。
如果没有通过 ModelAdmin.fields 或 ModelAdmin.fielets 定义明确的顺序就使用 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,在管理更改表格时启用 “另存为新” 功能。
通常情况下,对象有三个保存选项。“保存”、“保存并继续编辑” 和 “保存并添加另一个”。如果 save_as 为 True,则 “保存并添加另一个” 将被 “另存为新” 按钮所取代,该按钮将创建一个新的对象(具有新的 ID),而不是更新现有的对象。
默认情况下,save_as 被设置为 False。
ModelAdmin.save_as_continue
当 save_as=True 时,保存新对象后默认重定向到该对象的变更视图。如果设置 save_as_continue=False,则重定向到变更列表视图。
默认情况下,save_as_continue 被设置为 True。
ModelAdmin.save_on_top
设置 save_on_top 来在你的管理更改表格的顶部添加保存按钮。
通常情况下,保存按钮只出现在表格的底部。如果设置 save_on_top,按钮将同时出现在顶部和底部。
默认情况下,save_on_top 被设置为 False。
ModelAdmin.search_fields
设置 search_fields,在管理更改列表页面上启用搜索框。这应该被设置为字段名的列表,每当有人在该文本框中提交搜索查询时,就会被搜索到。
这些字段应该是某种文本字段,如 CharField 或 TextField。你也可以对 ForeignKey 或 ManyToManyField 进行相关查询,并使用查找 API “follow” 符号:
search_fields = ["foreign_key__related_fieldname"]
例如,如果你有一个有作者的博客条目,下面的定义将可以通过作者的电子邮件地址搜索博客条目:
search_fields = ["user__email"]
当有人在管理搜索框中进行搜索时,Django 会将搜索查询拆分成多个词,并返回所有包含这些词的对象,不区分大小写(使用 icontains 查找),其中每个词必须在 search_fields 中至少有一个。例如,如果 search_fields 设置为 ['first_name', 'last_name'],用户搜索 john lennon',Django 会做相当于这个 SQL WHERE 子句。
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 会做相当于这个 SQL 的 WHERE 子句:
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 |
| None | 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
默认情况下,变更列表页面允许按 list_display 中指定的所有模型字段(以及使用 display() 装饰器的 ordering 参数或具有 admin_order_field 属性的可调用对象)进行排序。
如果你想禁止对某些列进行排序,请将 sortable_by 设置为你想排序的 list_display 子集的一个集合(例如 list 、tuple或set`)。一个空的集合会禁用所有列的排序。
如果你需要动态地指定这个列表,可以实现一个 get_sortable_by() 方法来代替。
ModelAdmin.view_on_site
设置 view_on_site 来控制是否显示 “在站点上查看” 链接。这个链接应该把你带到一个可以显示保存对象的 URL。
这个值可以是一个布尔标志,也可以是一个可调用对象。如果 True (默认),对象的 get_absolute_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() 使用的自定义模板的路径。
(本文超出站点单文档体积上限,已按小节截断)
