Django管理网站

Django最强大的部分之一是自动管理界面。它从模型中读取元数据,以提供一个快速的、以模型为中心的界面,在该界面中,受信任的用户可以管理您站点上的内容。管理员建议的使用仅限于组织的内部管理工具。它不是用来构建整个前端的。

管理员有许多用于定制的钩子,但是要小心尝试专门使用这些钩子。如果您需要提供一个更以流程为中心的接口来抽象数据库表和字段的实现细节,那么可能是时候编写自己的视图了。

在本文档中,我们将讨论如何激活、使用和自定义Django的管理界面。

概述

在使用的默认项目模板中启用了管理员 startproject .

如果不使用默认项目模板,则需要满足以下要求:

  1. 添加 'django.contrib.admin' 及其依赖性- django.contrib.authdjango.contrib.contenttypesdjango.contrib.messagesdjango.contrib.sessions -给你 INSTALLED_APPS 设置。

  2. 配置一个 DjangoTemplates 在你的后端 TEMPLATES 设置与 django.template.context_processors.requestdjango.contrib.auth.context_processors.authdjango.contrib.messages.context_processors.messages'context_processors' 选择权 OPTIONS .

  3. 如果你已经定制了 MIDDLEWARE 设置, django.contrib.auth.middleware.AuthenticationMiddlewaredjango.contrib.messages.middleware.MessageMiddleware 必须包括在内。

  4. Hook the admin's URLs into your URLconf .

完成这些步骤后,您可以通过访问链接到的URL来使用管理网站。 (/admin/ 默认情况下)。

如果需要创建用于登录的用户,请使用 createsuperuser 指挥部。默认情况下,登录到管理员要求用户具有 is_staff 属性设置为 True

最后,确定在管理界面中哪些应用程序模型应该是可编辑的。对于这些模型中的每一个,请向管理员注册它们,如中所述。 ModelAdmin .

其他主题

参见

有关为与生产中的管理员关联的静态文件(图像、javascript和css)提供服务的信息,请参阅 服务文件 .

有问题吗?尝试 常见问题解答:行政管理 .

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) .

发现管理文件

当你放 'django.contrib.admin' 在你 INSTALLED_APPS 设置,Django自动查找 admin 并导入每个应用程序中的模块。

class apps.AdminConfig

这是默认值 AppConfig 管理类。它叫 autodiscover() 当 Django 开始的时候。

class apps.SimpleAdminConfig

这个班的工作原理是 AdminConfig ,除非它不叫 autodiscover() .

default_site

指向默认管理站点类或返回站点实例的可调用文件的点式导入路径。默认为 'django.contrib.admin.sites.AdminSite' . 见 覆盖默认管理网站 供使用。

autodiscover()[源代码]

此函数尝试导入 admin 每个已安装应用程序中的模块。这些模块需要向管理员注册模型。

通常,您不需要将此函数直接调用为 AdminConfig 当Django启动时调用它。

如果使用自定义 AdminSite ,导入所有 ModelAdmin 子类到代码中,并将它们注册到自定义 AdminSite . 在这种情况下,为了禁用自动发现,您应该 'django.contrib.admin.apps.SimpleAdminConfig' 而不是 'django.contrib.admin' 在你 INSTALLED_APPS 设置。

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 以…的名义 DateFieldDateTimeField 在您的模型中,更改列表页面将包含该字段基于日期的向下导航。

例子::

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-"

您还可以覆盖 empty_value_display 所有管理页面 AdminSite.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 仅包括 nametitle 字段,您将指定 fieldsexclude 这样地::

from django.contrib import admin


class AuthorAdmin(admin.ModelAdmin):
    fields = ["name", "title"]


class AuthorAdmin(admin.ModelAdmin):
    exclude = ["birth_date"]

由于作者模型只有三个字段, nametitlebirth_date ,由上述声明生成的表单将包含完全相同的字段。

ModelAdmin.fields

使用 fields 在“添加”和“更改”页上对表单进行简单布局更改的选项,例如仅显示可用字段的子集、修改其顺序或将其分组为行。例如,可以为 django.contrib.flatpages.models.FlatPage 型号如下:

class FlatPageAdmin(admin.ModelAdmin):
    fields = ["url", "title", "content"]

在上面的示例中,只有字段 urltitlecontent 将按顺序显示在窗体中。 fields 可以包含在中定义的值 ModelAdmin.readonly_fields 显示为只读。

有关更复杂的布局需求,请参见 fieldsets 选择权。

这个 fields 选项接受的值类型与 list_display ,但不接受可调用文件。仅当模型和模型管理方法的名称列在 readonly_fields .

要在同一行中显示多个字段,请将这些字段包装在它们自己的元组中。在这个例子中, urltitle 字段将显示在同一行和 content 字段将显示在它们的下方,并以其自身的行显示:

class FlatPageAdmin(admin.ModelAdmin):
    fields = [("url", "title"), "content"]

可能会与 ModelAdmin.fieldsets 选择权

这个 fields 选项不应与 fields 字典键 fieldsets 选项,如下一节所述。

如果既不 fields 也不 fieldsets 存在选项,Django将默认显示非 AutoField 并且有 editable=True 在单个字段集中,与在模型中定义的字段顺序相同。

ModelAdmin.fieldsets

集合 fieldsets 控制管理“添加”和“更改”页面的布局。

fieldsets 是一个二元组列表,其中每个二元组表示一个 <fieldset> 在管理表单页面上。(A) <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"],
            },
        ),
    ]

这将生成一个管理页面,其外观如下:

../../../_images/fieldsets.png

如果既不 fieldsets 也不 fields 存在选项,Django将默认显示非 AutoField 并且有 editable=True 在单个字段集中,与在模型中定义的字段顺序相同。

这个 field_options 字典可以有以下键:

  • fields

    要在此字段集中显示的字段名称列表或元组。此密钥是必需的。

    例子::

    {
        "fields": ["first_name", "last_name", "address", "city", "state"],
    }
    

    如同 fields 选项,若要在同一行上显示多个字段,请将这些字段包装在它们自己的元组中。在这个例子中, first_namelast_name 字段将显示在同一行:

    {
        "fields": [("first_name", "last_name"), "address", "city", "state"],
    }
    

    fields 可以包含在中定义的值 readonly_fields 显示为只读。

    如果将可调用的名称添加到 fields ,同样的规则也适用于 fields 选项:可调用文件必须列在 readonly_fields .

  • classes

    包含要应用于字段集的额外CSS类的列表或元组。

    例子::

    {
        "classes": ["wide", "extrapretty"],
    }
    

    默认管理网站样式表定义的两个有用类是 collapsewide . 字段集 collapse 样式最初将在管理中折叠,并替换为一个小的“单击以展开”链接。字段集 wide 样式将被赋予额外的水平空间。

  • description

    在每个字段集的顶部、字段集标题下显示的可选额外文本字符串。此字符串不是为呈现的 TabularInline 因为它的布局。

    注意这个值是 not HTML在管理界面中显示时被转义。如果您愿意,这允许您包含HTML。或者,您可以使用纯文本和 django.utils.html.escape() 以转义任何HTML特殊字符。

ModelAdmin.filter_horizontal

默认情况下,A ManyToManyField 在管理站点中显示 <select multiple> . 但是,在选择多个项目时,很难使用多个选择框。添加一个 ManyToManyField 对于这个列表,将使用一个漂亮的、不引人注目的javascript“过滤器”接口,允许在选项中进行搜索。未选定和选定的选项并排显示在两个框中。见 filter_vertical 使用垂直界面。

ModelAdmin.filter_vertical

等同于 filter_horizontal ,但使用过滤器界面的垂直显示,未选定选项框显示在选定选项框的上方。

ModelAdmin.form

默认情况下 ModelForm 是为模型动态创建的。它用于创建添加/更改页面上显示的表单。你可以很容易地提供你自己的 ModelForm 覆盖“添加/更改”页上的任何默认表单行为。或者,您可以自定义默认表单,而不是使用 ModelAdmin.get_form() 方法。

有关示例,请参见部分 向管理员添加自定义验证 .

省略 Meta.model 属性

如果你定义了 Meta.model 属性上的 ModelForm ,您还必须定义 Meta.fields 属性(或 Meta.exclude 属性)。但是,由于管理员有自己的定义字段的方式,因此 Meta.fields 属性将被忽略。

如果 ModelForm 只用于管理员,最简单的解决方案是省略 Meta.model 属性,因为 ModelAdmin 将提供正确的模型。或者,您可以设置 fields = []Meta 类以满足对 ModelForm .

ModelAdmin.exclude 优先

如果你 ModelFormModelAdmin 两者都定义了 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 是一个字典,将字段类映射到要在构造时传递给字段的参数dict。

因为这有点抽象,我们来看一个具体的例子。最常用的 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},
    }

注意字典中的键是实际的字段类, not 一个字符串。该值是另一个字典;这些参数将传递到表单域的 __init__() 方法。见 表单API 有关详细信息。

警告

如果您想将自定义小部件与关系字段(即 ForeignKeyManyToManyField )确保您没有将该字段的名称包含在 raw_id_fieldsradio_fieldsautocomplete_fields .

formfield_overrides 不允许您更改关系字段的小部件 raw_id_fieldsradio_fieldsautocomplete_fields 集合。那是因为 raw_id_fieldsradio_fieldsautocomplete_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将显示一个漂亮的“是”、“否”或“未知”图标,而不是 TrueFalse ,或 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 ,空字符串或不带元素的iterable,将显示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 或返回 TrueFalse ,或 None ,Django将显示一个漂亮的“是”、“否”或“未知”图标。 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 first_name 试图排序时的字段 colored_first_name 在行政管理中。

    属性指示降序 ordering 参数,您可以在字段名上使用连字符前缀。使用上面的示例,如下所示:

    @admin.display(ordering="-first_name")
    def colored_first_name(self):
        ...
    

    这个 ordering 参数支持查询查找,以便按相关模型上的值排序。此示例在列表显示中包含“Author First Name”列,并允许按First Name::

    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
    

    Query expressions 可以与 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() 函数和 not 这个 @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输出中 column-<field_name> 在每一个 <th> 元素。例如,这可以用于设置CSS文件中的列宽。

  • Django将尝试解释 list_display 按此顺序:

    • 模型的字段。

    • 可赎回的

    • 一个表示 ModelAdmin 属性。

    • 表示模型属性的字符串。

    例如,如果你有 first_name 作为模型字段和 ModelAdmin 属性,将使用模型字段。

使用 list_display_links 控制if和哪个字段 list_display 应链接到对象的“更改”页。

默认情况下,“更改列表”页将链接第一列——在中指定的第一个字段。 list_display --到每个项目的更改页。但是 list_display_links 允许您更改:

  • 设置为 None 完全没有链接。

  • 将其设置为字段列表或元组(格式与 list_display )您要将其列转换为链接。

    可以指定一个或多个字段。只要字段出现在 list_display ,Django不关心链接了多少(或多少)个字段。唯一的要求是如果你想使用 list_display_links 以这种方式,你必须定义 list_display .

在这个例子中, first_namelast_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_editablelist_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 .

集合 list_select_related 告诉Django使用 select_related() 在“管理更改列表”页上检索对象列表时。这可以为您节省大量的数据库查询。

值应该是布尔值、列表或元组。默认是 False .

当价值是 Trueselect_related() 将始终被调用。当值设置为 False ,Django会看 list_display 并调用 select_related() 如果有的话 ForeignKey 是存在的。

如果需要更细粒度的控制,请使用元组(或列表)作为 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 忽略此属性 select_related() 已在变更列表中调用 QuerySet .

ModelAdmin.ordering

集合 ordering 指定如何在Django管理视图中排列对象列表。这应该是与模型的列表或元组格式相同的列表或元组 ordering 参数。

如果没有提供,django管理员将使用模型的默认排序。

如果需要指定动态顺序(例如,取决于用户或语言),可以实现 get_ordering() 方法。

排序和排序时的性能考虑

为了确保结果的确定顺序,变更列表添加了 pk 如果找不到提供总排序的单个或唯一字段集,则返回排序。

例如,如果默认的排序方式是非唯一的 name 字段,然后更改列表按 namepk . 如果您有很多行并且没有索引,这可能会执行得很差。 namepk .

ModelAdmin.paginator

要用于分页的分页器类。默认情况下, django.core.paginator.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 不接受 DateTimeFieldForeignKeyOneToOneFieldManyToManyField 领域。

ModelAdmin.preserve_filters

默认情况下,在创建、编辑或删除对象后,应用的过滤器将保留在列表视图中。通过将此属性设置为,可以清除过滤器 False .

ModelAdmin.show_facets
New in Django 5.0.

控制是否为管理员更改列表中的筛选器显示方面计数。默认为 ShowFacets.ALLOW

显示时,小平面计数将根据当前应用的过滤器进行更新。

class ShowFacets
New in 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_facetsShowFacets.NEVER 要完全禁用镶嵌面,请执行以下操作。

ModelAdmin.radio_fields

默认情况下,Django的管理员将选择框界面(<select>)用于以下字段: ForeignKey 或有 choices 集合。如果字段存在于 radio_fields ,Django将使用一个单选按钮界面。假设 group 是一个 ForeignKeyPerson 型号:

class PersonAdmin(admin.ModelAdmin):
    radio_fields = {"group": admin.VERTICAL}

你可以选择使用 HORIZONTALVERTICALdjango.contrib.admin 模块。

不包括字段 radio_fields 除非它是 ForeignKey 或有 choices 集合。

ModelAdmin.autocomplete_fields

autocomplete_fields 是一个列表 ForeignKey 和/或 ManyToManyField 要更改为的字段 Select2 自动完成输入。

默认情况下,管理员使用选择框界面 (<select> )对于那些领域。有时,您不希望在下拉列表中选择要显示的所有相关实例的开销。

select2输入看起来类似于默认输入,但带有一个异步加载选项的搜索功能。如果相关模型有多个实例,这将更快、更方便用户使用。

你必须定义 search_fields 在相关对象上 ModelAdmin 因为自动完成搜索使用它。

为了避免未经授权的数据泄漏,用户必须 viewchange 对相关对象的权限,以便使用自动完成功能。

结果的排序和分页由相关的 ModelAdminget_ordering()get_paginator() 方法。

在下面的示例中, ChoiceAdmin 有一个自动完成字段用于 ForeignKeyQuestion . 结果按筛选 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的管理员将选择框界面(<select>)用于以下字段: ForeignKey . 有时,您不希望产生必须选择要在下拉列表中显示的所有相关实例的开销。

raw_id_fields 是要更改为 Input 任何一个的小部件 ForeignKeyManyToManyField ::

class ArticleAdmin(admin.ModelAdmin):
    raw_id_fields = ["newspaper"]

这个 raw_id_fields Input 如果字段是 ForeignKey 如果字段是 ManyToManyField . 这个 raw_id_fields 小部件在字段旁边显示放大镜按钮,允许用户搜索和选择值:

../../../_images/raw_id_fields.png
ModelAdmin.readonly_fields

默认情况下,管理员将所有字段显示为可编辑。此选项中的任何字段(应为 listtuple )将其数据显示为“是”且不可编辑;它们也从 ModelForm 用于创建和编辑。请注意,当指定 ModelAdmin.fieldsModelAdmin.fieldsets 只读字段必须存在才能显示(否则将被忽略)。

如果 readonly_fields 在不定义显式排序方式的情况下使用 ModelAdmin.fieldsModelAdmin.fieldsets 它们将最后添加到所有可编辑字段之后。

只读字段不仅可以显示模型字段中的数据,还可以显示模型方法或 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_asTrue “保存并添加另一个”将替换为“另存为新”按钮,该按钮创建新对象(具有新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 启用“管理更改列表”页上的搜索框。这应该设置为每当有人在该文本框中提交搜索查询时将搜索的字段名列表。

这些字段应该是某种文本字段,例如 CharFieldTextField . 您还可以对 ForeignKeyManyToManyField 使用lookup 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 作为查找,您可以将任何查找附加到字段中。例如,您可以使用 exact 通过设置 search_fields['first_name__exact'] .

还提供了一些用于指定字段查找的(旧的)快捷方式。您可以在 search_fields 包含以下字符,相当于添加 __<lookup> 现场:

前缀

查找

^

startswith

=

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 收藏(例如 listtupleset )的子集 list_display 你想分类的。空集合禁用所有列的排序。

如果需要动态指定此列表,请实现 get_sortable_by() 方法。

ModelAdmin.view_on_site

集合 view_on_site 控制是否显示“现场查看”链接。此链接应将您带到一个URL,您可以在其中显示保存的对象。

该值可以是布尔标志,也可以是可调用的。如果 True (默认),对象的 get_absolute_url() 方法将用于生成URL。

如果你的模型有 get_absolute_url() 方法,但不希望出现“View on site”按钮,只需设置 view_on_siteFalse ::

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 删除一个或多个对象时显示确认页的操作方法。见 actions documentation .

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 和A QuerySet 要删除的对象。重写此方法以自定义“删除选定对象”的删除过程 action .

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 作为参数,应返回 listtuple 订购类似于 ordering 属性。例如::

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 .

此方法可能会被您自己的自定义搜索方法覆盖。例如,您可能希望按整型字段进行搜索,或使用外部工具,如 SolrHaystack 。您必须确定您的搜索方法实现的查询集更改是否会在结果中引入重复项,并返回 True 返回值的第二个元素中。

例如,搜索 nameage ,您可以使用:

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 并期望返回 listtuple 的字段名,将使用自动完成小部件显示,如上文中所述。 ModelAdmin.autocomplete_fields 部分。

ModelAdmin.get_readonly_fields(request, obj=None)

这个 get_readonly_fields 方法给出了 HttpRequest 以及 obj 正在编辑(或 None 并将返回 listtuple 将显示为只读的字段名,如上文中所述 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 并期望返回 listtuple 将在ChangeList视图中显示的字段名,如上文中所述。 ModelAdmin.list_display 部分。

这个 get_list_display_links 方法给出了 HttpRequest 以及 listtuple 返回的 ModelAdmin.get_list_display() . 预计它将返回 None 或A listtuple 更改列表中将链接到更改视图的字段名,如中所述。 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 在Add窗体上),并预期返回一个二元组列表,其中每个二元组表示一个 <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 并期望返回一个集合(例如 listtupleset )在“更改列表”页中可排序的字段名。

其默认实现返回 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 并将返回 listtuple 属于 InlineModelAdmin 对象,如下所述 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 在add form上),并应返回一个iterable的inlines。您可以重写此方法以根据请求或模型实例动态添加内联,而不是在中指定它们 ModelAdmin.inlines .

ModelAdmin.get_urls()[源代码]

这个 get_urls 对象上的方法 ModelAdmin 以与URLconf相同的方式返回要用于该ModelAdmin的URL。因此,您可以扩展它们,如中所述 URL调度器 ,使用 AdminSite.admin_view() 您的视图的包装::

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 。这一点很重要,因为它确保了两件事:

  1. 运行权限检查,确保只有活动的员工用户可以访问该视图。

  2. 这个 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)[源代码]

返回A ModelForm 用于管理添加和更改视图的类,请参见 add_view()change_view() .

基本实现使用 modelform_factory() 子类 form ,由属性修改,例如 fieldsexclude . 因此,例如,如果您想向超级用户提供额外的字段,您可以使用不同的基本形式进行交换,例如:

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)[源代码]

产量 (FormSetInlineModelAdmin )用于管理添加和更改视图的对。

例如,如果只想在更改视图中显示特定的内联,则可以重写 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)

这个 formfield_for_foreignkey A方法 ModelAdmin 允许您重写外键字段的默认FormField。例如,要基于用户返回此外键字段的对象子集,请执行以下操作:

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 方法可以重写以更改多对多字段的默认FormField。例如,如果一个车主可以拥有多辆车,并且车可以属于多个车主——多对多关系——那么您可以过滤 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_foreignkeyformfield_for_manytomany 方法, formfield_for_choice_field 方法可以重写以更改已声明选项的字段的默认FormField。例如,如果超级用户可用的选项应与普通员工可用的选项不同,则可以按以下步骤进行操作:

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)[源代码]

返回A ModelForm 在中使用的类 Formset 在变更列表页上。要使用自定义表单,例如:

from django import forms


class MyForm(forms.ModelForm):
    pass


class MyModelAdmin(admin.ModelAdmin):
    def get_changelist_form(self, request, **kwargs):
        return MyForm

省略 Meta.model 属性

如果你定义了 Meta.model 属性上的 ModelForm ,您还必须定义 Meta.fields 属性(或 Meta.exclude 属性)。然而, ModelAdmin 忽略此值,并用 ModelAdmin.list_editable 属性。最简单的解决方案是忽略 Meta.model 属性,因为 ModelAdmin 将提供正确的模型。

ModelAdmin.get_changelist_formset(request, **kwargs)[源代码]

返回A ModelFormSet 在ChangeList页上使用的类,如果 list_editable 使用。要使用自定义表单集,例如:

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() (例如) user__email=user@example.com )由于查询字符串中的查找可以由用户操作,因此必须对其进行清理,以防止未经授权的数据暴露。

这个 lookup_allowed() 方法被赋予来自查询字符串的查找路径(例如 'user__email' )、相应的值(例如 'user@example.com' )和请求,并返回一个布尔值,指示是否过滤更改列表的 QuerySet 允许使用参数。如果 lookup_allowed() 退货 FalseDisallowedModelAdminLookup (子类 SuspiciousOperation )被提出。

默认情况下, lookup_allowed() 允许访问模型的本地字段,字段路径用于 list_filter (但不是从 get_list_filter() )和所需的查找 limit_choices_to 在…中正常工作 raw_id_fields .

重写此方法以自定义 ModelAdmin 子类。

Changed in Django 5.0:

这个 request 添加了参数。

ModelAdmin.has_view_permission(request, obj=None)

应该返回 True 如果查看 obj 是允许的, False 否则。如果OBJ是 None 应该回归 TrueFalse 指示一般情况下是否允许查看此类型的对象(例如, False 将解释为当前用户不允许查看任何此类对象)。

默认实现返回 True 如果用户具有“更改”或“查看”权限。

ModelAdmin.has_add_permission(request)

应该返回 True 如果允许添加对象, False 否则。

ModelAdmin.has_change_permission(request, obj=None)

应该返回 True 中频编辑 obj 是允许的, False 否则。如果 objNone 应该回归 TrueFalse 指示一般情况下是否允许编辑此类型的对象(例如, False 将被解释为当前用户不允许编辑此类型的任何对象)。

ModelAdmin.has_delete_permission(request, obj=None)

应该返回 True 如果删除 obj 是允许的, False 否则。如果 objNone 应该回归 TrueFalse 指示一般情况下是否允许删除此类型的对象(例如, 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 A方法 ModelAdmin 返回A 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 后端。见 custom ModelAdmin example .

关键字参数允许您更改消息级别、添加额外的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() 以及“删除所选内容” action .

这个 objs 参数是对象的同构不可迭代(a QuerySet 或要删除的模型实例列表),以及 requestHttpRequest .

此方法必须返回 (deleted_objects, model_count, perms_needed, protected) .

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 documentation .

ModelAdmin 资产定义

有时您希望在添加/更改视图中添加一些CSS和/或javascript。这可以通过使用 Media 你的内部阶级 ModelAdmin ::

class ArticleAdmin(admin.ModelAdmin):
    class Media:
        css = {
            "all": ["my_styles.css"],
        }
        js = ["my_code.js"]

这个 staticfiles app 预置 STATIC_URL (或) MEDIA_URL 如果 STATIC_URLNone )任何资产路径。同样的规则也适用于 regular asset definitions on forms .

JQuery

django管理javascript使用 jQuery 类库。

为了避免与用户提供的脚本或库冲突,Django的jQuery(版本3.7.1)被命名为 django.jQuery 。如果您想在您自己的管理脚本中使用jQuery而不包括第二个副本,您可以使用 django.jQuery 对象并添加/编辑视图。此外,您自己的管理表单或小部件取决于 django.jQuery 必须指定 js=['admin/js/jquery.init.js', …] 什么时候 declaring form media assets

Changed in Django 5.0:

JQuery从3.6.4升级到3.7.1。

这个 ModelAdmin 类默认需要jquery,因此不需要将jquery添加到 ModelAdmin 的媒体资源列表,除非您有特定需求。例如,如果您要求jquery库位于全局命名空间中(例如使用第三方jquery插件时),或者如果您需要较新版本的jquery,则必须包含自己的副本。

django提供jquery的未压缩和“小型”版本,如 jquery.jsjquery.min.js 分别。

ModelAdminInlineModelAdmin 有一个 media 返回的列表的属性 Media 存储窗体和/或窗体集的javascript文件路径的对象。如果 DEBUGTrue 它将返回各种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 否则,事情可能会破裂。见 forms 文件 custom validation 更具体地说, model form validation notes 更多信息。

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 超类)。共享功能包括:

这个 InlineModelAdmin 类添加或自定义:

InlineModelAdmin.model

内联使用的模型。这是必需的。

InlineModelAdmin.fk_name

模型上的外键的名称。在大多数情况下,这将自动处理,但是 fk_name 如果同一父模型有多个外键,则必须显式指定。

InlineModelAdmin.formset

默认为 BaseInlineFormSet . 使用您自己的表单集可以为您提供许多自定义的可能性。周围建有进水口 model formsets .

InlineModelAdmin.form

价值 form 默认为 ModelForm . 这是传递给 inlineformset_factory() 为该内联创建表单集时。

警告

为编写自定义验证时 InlineModelAdmin 对于依赖父模型特性的验证,请谨慎编写。如果父模型未能验证,则它可能处于不一致状态,如中的警告所述。 A的验证 ModelForm .

InlineModelAdmin.classes

包含要应用于为内联呈现的字段集的额外CSS类的列表或元组。默认为 None . 与在中配置的类相同 fieldsets ,带 collapse 类最初将折叠,它们的头将有一个小的“显示”链接。

InlineModelAdmin.extra

这控制除了初始表单外,表单集还将显示的额外表单的数量。默认为3。见 formsets documentation 更多信息。

对于启用了javascript的浏览器的用户,提供了一个“添加另一个”链接,以便除了由于 extra 参数。

如果当前显示的表单数超过 max_num 或者如果用户没有启用javascript。

InlineModelAdmin.get_extra() 还允许您自定义额外表单的数量。

InlineModelAdmin.max_num

这将控制要在内联中显示的最大表单数。这与对象数量没有直接关联,但如果值足够小,则可以关联。见 限制可编辑对象的数量 更多信息。

InlineModelAdmin.get_max_num() 还允许您自定义最大数量的额外表单。

InlineModelAdmin.min_num

这将控制要在内联中显示的最小表单数。见 modelformset_factory() 更多信息。

InlineModelAdmin.get_min_num() 还允许您自定义所显示表单的最小数目。

InlineModelAdmin.raw_id_fields

默认情况下,Django的管理员将选择框界面(<select>)用于以下字段: ForeignKey . 有时,您不希望产生必须选择要在下拉列表中显示的所有相关实例的开销。

raw_id_fields 是要更改为 Input 任何一个的小部件 ForeignKeyManyToManyField ::

class BookInline(admin.TabularInline):
    model = Book
    raw_id_fields = ["pages"]
InlineModelAdmin.template

用于在页面上呈现内联的模板。

InlineModelAdmin.verbose_name

属性的重写 verbose_name 从模特的内心 Meta 班级。

InlineModelAdmin.verbose_name_plural

属性的重写 verbose_name_plural 从模特的内心 Meta 班级。如果没有给出这一点,并且 InlineModelAdmin.verbose_name 定义后,Django将使用 InlineModelAdmin.verbose_name + 's'

InlineModelAdmin.can_delete

指定是否可以在内联中删除内联对象。默认为 True .

指定可在管理员中更改的内联对象是否具有指向更改表单的链接。默认为 False .

InlineModelAdmin.get_formset(request, obj=None, **kwargs)

返回A 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 正在编辑的父对象。

备注

这个 obj 参数传递给 InlineModelAdmin 方法是正在编辑的父对象,或者 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的管理员 not 显示这个小部件-否则您将在管理关系的管理页面上得到两个小部件。

请注意,使用此技术时, m2m_changed 信号不会触发。这是因为在行政方面, through 只是一个具有两个外键字段的模型,而不是多对多关系。

在所有其他方面, InlineModelAdmin 和其他的完全一样。您可以使用任何标准 ModelAdmin 性质。

使用多对多中介模型

当您使用 through 对A的论证 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

此示例使用默认值 InlineModelAdmin 值为 Membership 建模,并将额外的添加表单限制为一个。这可以使用任何可用的选项进行定制 InlineModelAdmin 类。

现在为创建管理视图 PersonGroup 模型::

class PersonAdmin(admin.ModelAdmin):
    inlines = [MembershipInline]


class GroupAdmin(admin.ModelAdmin):
    inlines = [MembershipInline]

最后,注册您的 PersonGroup 管理站点的模型:

admin.site.register(Person, PersonAdmin)
admin.site.register(Group, GroupAdmin)

现在您的管理站点设置为编辑 Membership 对象从 PersonGroup 详细页面。

将泛型关系用作内联

可以将内联与一般相关的对象一起使用。假设您有以下型号:

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)

如果要允许编辑和创建 Image 实例上 Product ,添加/更改可使用的视图 GenericTabularInlineGenericStackedInline (两个子类 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 documentation 更具体的信息。

覆盖管理模板

您可以覆盖管理模块用于生成管理站点的各个页面的许多模板。你甚至可以为一些特定的应用程序覆盖这些模板。

设置项目管理模板目录

管理模板文件位于 django/contrib/admin/templates/admin 目录。

为了覆盖其中的一个或多个,首先创建 admin 项目中的目录 templates 目录。这可以是您在 DIRS 选择权 DjangoTemplates 后端在 TEMPLATES 设置。如果你已经定制了 'loaders' 选项,确定 'django.template.loaders.filesystem.Loader' 出现之前 'django.template.loaders.app_directories.Loader' 以便模板加载系统在包含自定义模板之前找到这些模板 django.contrib.admin .

在这里面 admin 目录,创建以应用程序命名的子目录。在这些应用程序子目录中,创建以模型命名的子目录。注意,在查找目录时,管理应用程序会将模型名称小写,因此,如果要在区分大小写的文件系统上运行应用程序,请确保将目录名称全部小写。

要覆盖特定应用程序的管理模板,请从复制并编辑模板 django/contrib/admin/templates/admin 目录,并将其保存到您刚刚创建的一个目录中。

例如,如果我们想为名为 my_app 我们会复制 contrib/admin/templates/admin/change_list.htmltemplates/admin/my_app/ 我们的项目目录,并做任何必要的更改。

如果我们只想为名为“page”的特定模型向“更改列表”视图中添加一个工具,我们会将该文件复制到 templates/admin/my_app/page 我们项目的目录。

重写与替换管理模板

由于管理模板的模块化设计,通常不需要也不建议替换整个模板。最好只覆盖模板中需要更改的部分。

要继续上面的示例,我们希望在 History 工具 Page 模型。看了之后 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 目录,我们的链接将显示在我的应用程序中所有型号的更改表单上。

每个应用程序或模型可以覆盖的模板

不是每个模板都在 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_templateAdminSite.login_templateAdminSite.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 实例。

如果要自定义默认管理网站,可以 override it .

在构造 AdminSite ,您可以使用 name 构造函数的参数。此实例名称用于标识实例,尤其是在 reversing admin URLs . 如果未提供实例名称,则默认实例名称为 admin 将被使用。见 定制 AdminSite 班 例如自定义 AdminSite 类。

django.contrib.admin.sites.all_sites

A WeakSet 包含所有管理站点实例。

AdminSite 属性

模板可以覆盖或扩展基本管理模板,如中所述。 覆盖管理模板 .

AdminSite.site_header

要放在每个管理页面顶部的文本,如 <div> (字符串)。默认情况下,这是“Django管理”。

Changed in Django 5.0:

在较旧的版本中, site_header 正在使用一种 <h1> 标签。

AdminSite.site_title

要放在每个管理页末尾的文本 <title> (字符串)默认情况下,这是“Django站点管理”。

AdminSite.site_url

每个管理页面顶部的“查看站点”链接的URL。默认情况下, site_url is /. Set it to `` none``删除链接。

对于在子路径上运行的站点, each_context() 方法检查当前请求是否具有 request.META['SCRIPT_NAME'] 如果 site_url 不是设置为 / .

AdminSite.index_title

要放在管理索引页顶部的文本(字符串)。默认情况下,这是“网站管理”。

AdminSite.index_template

管理网站主索引视图将使用的自定义模板的路径。

AdminSite.app_index_template

管理网站应用程序索引视图将使用的自定义模板的路径。

AdminSite.empty_value_display

用于在管理网站的更改列表中显示空值的字符串。默认为短划线。该值也可以在Per上重写 ModelAdmin 基于自定义字段 ModelAdmin 通过设置 empty_value_display 字段的属性。见 ModelAdmin.empty_value_display 举个例子。

AdminSite.enable_nav_sidebar

一个布尔值,用于确定是否在更大的屏幕上显示导航边栏。默认设置为 True .

AdminSite.final_catch_all_view

一个布尔值,它确定是否向将未经身份验证的用户重定向到登录页的管理员添加最终的全部捕获视图。默认情况下,它设置为 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 :应用程序列表 application registry 可供当前用户使用。列表中的每个条目都是一个dict,用以下键表示应用程序:

    • app_label :应用程序标签

    • app_url :管理中应用程序索引的URL

    • has_module_perms :一个布尔值,指示当前用户是否允许显示和访问模块的索引页。

    • models :应用程序中可用的模型列表

    每个模型都是一个具有以下键的dict:

    • model :模范班

    • object_name :模型的类名

    • name :模型的复数名称

    • perms 答: dict 跟踪 addchangedeleteview 权限

    • admin_url :模型的管理员变更列表URL

    • add_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)[源代码]

方法返回应用程序列表。 application registry 可供当前用户使用。您可以选择将一个 app_label 参数以获取单个应用程序的详细信息。列表中的每个条目都是一个词典,表示具有以下关键字的应用程序:

  • app_label :应用程序标签

  • app_url :管理中应用程序索引的URL

  • has_module_perms :一个布尔值,指示当前用户是否允许显示和访问模块的索引页。

  • models :应用程序中可用的模型列表

  • name :应用程序的名称

每个型号都是一本词典,其中包含以下关键字:

  • model :模范班

  • object_name :模型的类名

  • name :模型的复数名称

  • perms 答: dict 跟踪 addchangedeleteview 权限

  • admin_url :模型的管理员变更列表URL

  • add_url :用于添加新模型实例的管理URL

应用程序和型号的列表按其名称的字母顺序排序。您可以重写此方法以更改管理索引页上的默认顺序。

AdminSite.has_permission(request)[源代码]

返回 True 如果给定的用户 HttpRequest 有权限查看管理网站中的至少一个页面。默认为同时要求 User.is_activeUser.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)[源代码]
New in Django 5.0.

返回给定模型类的管理类。加薪 django.contrib.admin.exceptions.NotRegistered 如果模特没有注册。

AdminSite.get_log_entries(request)[源代码]
New in Django 5.0.

返回相关的 LogEntry 实例,显示在站点索引页上。可以覆盖此方法以按其他条件筛选日志条目。

挂钩 AdminSite 到您的urlconf中的实例

设置django管理员的最后一步是 AdminSite 实例到您的urlconf中。通过将给定的URL指向 AdminSite.urls 方法。不需要使用 include() .

在这个示例中,我们注册默认值 AdminSite 实例 django.contrib.admin.site 在URL处 /admin/ ::

# 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 子类。

myapp/admin.py
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)
myproject/urls.py
from django.urls import path

from myapp.admin import admin_site

urlpatterns = [
    path("myadmin/", admin_site.urls),
]

请注意,您可能不希望自动发现 admin 使用自己的模块时 AdminSite 实例,因为您可能会导入每个应用程序的所有 admin 你的模块 myproject.admin 模块。这意味着你需要 'django.contrib.admin.apps.SimpleAdminConfig' 而不是 'django.contrib.admin' 在你 INSTALLED_APPS 设置。

覆盖默认管理网站

您可以覆盖默认值 django.contrib.admin.site 通过设置 default_site 自定义的属性 AppConfigAdminSite 子类或返回站点实例的可调用项。

myproject/admin.py
from django.contrib import admin


class MyAdminSite(admin.AdminSite):
    ...
myproject/apps.py
from django.contrib.admin.apps import AdminConfig


class MyAdminConfig(AdminConfig):
    default_site = "myproject.admin.MyAdminSite"
myproject/settings.py
INSTALLED_APPS = [
    # ...
    "myproject.apps.MyAdminConfig",  # replaces 'django.contrib.admin'
    # ...
]

同一urlconf中的多个管理站点

您可以在同一个Django支持的网站上创建管理站点的多个实例。创建的多个实例 AdminSite 然后把它们放在不同的网址上。

在这个例子中,URL /basic-admin//advanced-admin/ 特性管理站点的单独版本--使用 AdminSite 实例 myproject.admin.basic_sitemyproject.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名称的前缀,用于 reversing them . 只有当您使用多个 AdminSite .

将视图添加到管理网站

就像 ModelAdminAdminSite 提供了一个 get_urls() 可以重写以定义网站的其他视图的方法。要向管理网站添加新视图,请扩展基础 get_urls() 方法来包含新视图的模式。

备注

您呈现的任何使用管理模板或扩展基本管理模板的视图都应设置 request.current_app 在呈现模板之前。它应该设置为 self.name 如果您的视图位于 AdminSiteself.admin_site.name 如果您的视图位于 ModelAdmin .

添加密码重置功能

您可以通过在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/ 并要求您将URL从 ^admin/ 在包含管理应用程序本身的行之前)。

存在 admin_password_reset 命名的URL将导致“忘记密码?”链接显示在密码框下的默认管理员登录页上。

LogEntry 对象

class models.LogEntry

这个 LogEntry 类跟踪通过管理接口完成的对象的添加、更改和删除。

LogEntry 属性

LogEntry.action_time

行动的日期和时间。

LogEntry.user

用户(AN) AUTH_USER_MODEL 实例)谁执行了操作。

LogEntry.content_type

这个 ContentType 修改对象的。

LogEntry.object_id

修改对象的主键的文本表示形式。

LogEntry.object_repr

对象的 repr() 修改后。

LogEntry.action_flag

记录的操作类型: ADDITIONCHANGEDELETION .

例如,要获取通过管理完成的所有添加的列表,请执行以下操作:

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 reversing system .

这个 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")

有关更多详细信息,请参阅 reversing namespaced URLs .

为了更容易地逆转模板中的管理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 上述实例。这个 opts 变量可以是具有 app_labelmodel_name 属性,通常由当前模型的管理视图提供。

这个 display 装饰师

display(*, boolean=None, ordering=None, description=None, empty_value=None)[源代码]

此修饰符可用于设置可与一起使用的自定义显示函数的特定属性 list_displayreadonly_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 参数,查询字符串变量中的原始请求路径由 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):
    ...