Skip to main content

Django管理网站

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

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

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

概述

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

供参考,这里有要求:

  1. 'django.contrib.admin' 添加到您的 INSTALLED_APPS 设置。

  2. 管理员有四个依赖项–django.contrib.authdjango.contrib.contenttypesdjango.contrib.messagesdjango.contrib.sessions。如果这些应用程序不在您的 INSTALLED_APPS 列表中,请添加它们。

  3. django.contrib.auth.context_processors.authdjango.contrib.messages.context_processors.messages 添加到您的 TEMPLATES 中定义的 DjangoTemplates 后端的 'context_processors' 选项以及 django.contrib.auth.middleware.AuthenticationMiddlewaredjango.contrib.messages.middleware.MessageMiddlewareMIDDLEWARE。默认情况下,这些都处于活动状态,因此您只需手动调整设置即可。

  4. 确定您的应用程序的模型应该在管理界面中可编辑。

  5. 对于每个模型,可选择创建一个 ModelAdmin 类,封装该特定模型的自定义管理功能和选项。

  6. 实例化 AdminSite 并告诉它关于你的每个模型和 ModelAdmin 类。

  7. AdminSite 实例挂接到您的URLconf中。

完成这些步骤后,您就可以使用您的Django管理网站,前往您连结的网址(预设为 /admin/)。如果需要创建用户登录,可以使用 createsuperuser 命令。

其他主题

参见

有关在生产中提供与管理员关联的静态文件(图像,JavaScript和CSS)的信息,请参阅 投放文件

有问题吗?尝试 常见问题:管理员

ModelAdmin 对象

class ModelAdmin

ModelAdmin 类是管理界面中模型的表示。通常,这些文件存储在您的应用程序中名为 admin.py 的文件中。让我们来看看一个非常简单的 ModelAdmin 示例:

from django.contrib import admin
from myproject.myapp.models import Author

class AuthorAdmin(admin.ModelAdmin):
    pass
admin.site.register(Author, AuthorAdmin)

你需要一个 ModelAdmin 对象吗?

在前面的示例中,ModelAdmin 类未定义任何自定义值。因此,将提供默认管理界面。如果您对默认管理界面感到满意,则不需要定义 ModelAdmin 对象 - 您可以注册模型类而不提供 ModelAdmin 描述。前面的例子可以简化为:

from django.contrib import admin
from myproject.myapp.models import Author

admin.site.register(Author)

register 装饰器

register(*models, site=django.admin.sites.site)

还有一个装饰器用于注册您的 ModelAdmin 类:

from django.contrib import admin
from .models import Author

@admin.register(Author)
class AuthorAdmin(admin.ModelAdmin):
    pass

它给一个或多个模型类注册 ModelAdmin 和一个可选的关键字参数 site 如果你不使用默认的 AdminSite:

from django.contrib import admin
from .models import Author, Reader, Editor
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)。如果你使用Python 3,不必担心支持Python 2,你可以使用 super().__init__(*args, **kwargs)。否则,你必须使用 admin.site.register(),而不是这个装饰。

发现管理文件

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

class apps.AdminConfig

这是admin的默认 AppConfig 类。当Django启动时,它调用 autodiscover()

class apps.SimpleAdminConfig

这个类的工作原理像 AdminConfig,除了它不调用 autodiscover()

autodiscover()

此功能尝试在每个已安装的应用程序中导入 admin 模块。这样的模块应该注册模型与管理员。

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

如果使用自定义 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

控制是否在操作下拉列表旁边显示选择计数器。默认情况下,admin更改列表将显示它(actions_selection_counter = True)。

ModelAdmin.date_hierarchy

date_hierarchy 设置为模型中的 DateFieldDateTimeField 的名称,更改列表页面将包括该字段的基于日期的向下钻取导航。

例:

date_hierarchy = 'pub_date'

这将基于可用数据智能地填充自身。如果所有日期都在一个月内,则只会显示日期级别。

注解

date_hierarchy 在内部使用 QuerySet.datetimes()。当启用时区支持(USE_TZ = True)时,请参阅其文档中的一些注意事项。

ModelAdmin.empty_value_display
New in Django 1.9.

此属性覆盖为空的记录字段的默认显示值(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):
    fields = ('name', 'title', 'view_birth_date')

    def view_birth_date(self, obj):
        return obj.birth_date

    view_birth_date.empty_value_display = '???'
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)

如果你想要一个只包括 nametitle 字段的 Author 模型的表单,你可以像这样指定 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 选项。

list_display 不同,fields 选项只能包含模型上的字段名称或 form 指定的格式。只有在 readonly_fields 中列出的情况下,它才可以包含可召集。

要在同一行上显示多个字段,请将这些字段包含在它们自己的元组中。在该示例中,urltitle 字段将显示在同一行上,并且 content 字段将在其自身的行下面显示:

class FlatPageAdmin(admin.ModelAdmin):
    fields = (('url', 'title'), 'content')

注意

fields 选项不应与 fieldsets 选项中的 fields 字典键混淆,如下一节所述。

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

ModelAdmin.fieldsets

设置 fieldsets 以控制管理“添加”和“更改”页面的布局。

fieldsets 是两元组的列表,其中每个两元组表示管理表单页上的 <fieldset>。 (<fieldset> 是形式的“节”)。

两元组的格式为 (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

默认情况下,ManyToManyField 在管理站点中显示为 <select multiple>。然而,当选择许多项目时,多重选择框可能难以使用。将 ManyToManyField 添加到此列表将改为使用一个漂亮的不引人注意的JavaScript“过滤器”接口,允许在选项内搜索。未选择和选定的选项并排显示在两个框中。请参见 filter_vertical 以使用垂直接口。

ModelAdmin.filter_vertical

filter_horizontal 相同,但使用过滤器界面的垂直显示,其中出现在所选选项框上方的未选择选项框。

ModelAdmin.form

默认情况下,将为您的模型动态创建 ModelForm。它用于创建在添加/更改页面上显示的表单。您可以轻松地提供您自己的 ModelForm 以覆盖添加/更改页面上的任何默认表单行为。或者,您可以自定义默认形式,而不是使用 ModelAdmin.get_form() 方法指定一个全新的形式。

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

注意

如果在 ModelForm 上定义 Meta.model 属性,则还必须定义 Meta.fields 属性(或 Meta.exclude 属性)。然而,由于管理员有自己的定义字段的方式,Meta.fields 属性将被忽略。

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

注意

如果您的 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.db import models
from django.contrib import admin

# Import our custom widget and our model from where they're defined
from myapp.widgets import RichTextEditorWidget
from myapp.models import MyModel

class MyModelAdmin(admin.ModelAdmin):
    formfield_overrides = {
        models.TextField: {'widget': RichTextEditorWidget},
    }

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

警告

如果要使用具有关系字段(即 ForeignKeyManyToManyField)的自定义窗口小部件,请确保您未在 raw_id_fieldsradio_fields 中包含该字段的名称。

formfield_overrides 将不允许您更改已设置 raw_id_fieldsradio_fields 的关系字段上的窗口小部件。这是因为 raw_id_fieldsradio_fields 意味着自己的定制小部件。

ModelAdmin.inlines

请参阅下面的 InlineModelAdmin 对象以及 ModelAdmin.get_formsets_with_inlines()

ModelAdmin.list_display

设置 list_display 以控制在管理员的更改列表页面上显示哪些字段。

例:

list_display = ('first_name', 'last_name')

如果不设置 list_display,管理站点将显示一个单独的列,显示每个对象的 __str__()__unicode__() on Python 2)表示形式。

您有四个可以在 list_display 中使用的可能值:

  • 模型的一个字段。例如:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name')
    
  • 用于接受模型实例的一个参数的可调用项。例如:

    def upper_case_name(obj):
        return ("%s %s" % (obj.first_name, obj.last_name)).upper()
    upper_case_name.short_description = 'Name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = (upper_case_name,)
    
  • 表示 ModelAdmin 上的属性的字符串。这与可调用的行为相同。例如:

    class PersonAdmin(admin.ModelAdmin):
        list_display = ('upper_case_name',)
    
        def upper_case_name(self, obj):
            return ("%s %s" % (obj.first_name, obj.last_name)).upper()
        upper_case_name.short_description = 'Name'
    
  • 表示模型上属性的字符串。这个行为几乎与可调用的相同,但在此上下文中的 self 是模型实例。这里有一个完整的模型示例:

    from django.db import models
    from django.contrib import admin
    
    class Person(models.Model):
        name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def decade_born_in(self):
            return self.birthday.strftime('%Y')[:3] + "0's"
        decade_born_in.short_description = 'Birth decade'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'decade_born_in')
    

关于 list_display 的一些特殊情况:

  • 如果字段是 ForeignKey,Django将显示相关对象的 __str__() (Python 2上的 __unicode__())。

  • 不支持 ManyToManyField 字段,因为这将需要为表中的每一行执行单独的SQL语句。如果你想这样做,给你的模型一个自定义方法,并将该方法的名称添加到 list_display。 (有关 list_display 中的自定义方法的更多信息,请参见下文)。

  • 如果字段是 BooleanFieldNullBooleanField,Django将显示一个漂亮的“on”或“off”图标,而不是 TrueFalse

  • 如果给定的字符串是模型的一个方法,ModelAdmin 或一个可调用的,Django将默认HTML转义输出。要转义用户输入并允许您自己的非转义标签,请使用 format_html()

    这里有一个完整的示例模型:

    from django.db import models
    from django.contrib import admin
    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)
    
        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')
    

    1.9 版后已移除: 在旧版本中,您可以向方法中添加 allow_tags 属性以防止自动转义。此属性已弃用,因为使用 format_html()format_html_join()mark_safe() 更安全。

  • 正如一些例子已经演示的,当使用可调用,模型方法或 ModelAdmin 方法时,您可以通过向可调用方添加 short_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')
    
        def birth_date_view(self, obj):
             return obj.birth_date
    
        birth_date_view.empty_value_display = 'unknown'
    
    New in Django 1.9:

    添加了自定义 empty_value_display 的能力。

  • 如果给定的字符串是模型的方法,ModelAdmin 或返回True或False的可调用方法如果您给方法一个值为 Trueboolean 属性,Django将显示一个漂亮的“on”或“off”图标。

    这里有一个完整的示例模型:

    from django.db import models
    from django.contrib import admin
    
    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        birthday = models.DateField()
    
        def born_in_fifties(self):
            return self.birthday.strftime('%Y')[:3] == '195'
        born_in_fifties.boolean = True
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('name', 'born_in_fifties')
    
  • __str__() (在Python 2上的 __unicode__())方法在 list_display 中与任何其他模型方法一样有效,因此完全可以这样做:

    list_display = ('__str__', 'some_other_field')
    
  • 通常,list_display 的不是实际数据库字段的元素不能用于排序(因为Django在数据库级别执行所有排序)。

    但是,如果 list_display 的元素表示某个数据库字段,您可以通过设置项目的 admin_order_field 属性来指示此事实。

    例如:

    from django.db import models
    from django.contrib import admin
    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)
    
        def colored_first_name(self):
            return format_html(
                '<span style="color: #{};">{}</span>',
                self.color_code,
                self.first_name,
            )
    
        colored_first_name.admin_order_field = 'first_name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'colored_first_name')
    

    以上将告诉Django按照 first_name 字段排序,当尝试在管理员中按 colored_first_name 排序。

    要使用 admin_order_field 指示降序,您可以在字段名称上使用连字符前缀。使用上面的例子,这看起来像:

    colored_first_name.admin_order_field = '-first_name'
    

    admin_order_field 支持查询查找以按相关模型上的值进行排序。此示例在列表显示中包含“作者名”列,并允许按名字排序:

    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')
    
        def author_first_name(self, obj):
            return obj.author.first_name
    
        author_first_name.admin_order_field = 'author__first_name'
    
  • list_display 的元素也可以是属性。但请注意,由于属性在Python中的工作方式,只有在使用 property() 函数和 @property 装饰器时,才能在属性上设置 short_description

    例如:

    class Person(models.Model):
        first_name = models.CharField(max_length=50)
        last_name = models.CharField(max_length=50)
    
        def my_property(self):
            return self.first_name + ' ' + self.last_name
        my_property.short_description = "Full name of the person"
    
        full_name = property(my_property)
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('full_name',)
    
  • list_display 中的字段名称也将作为CSS类在HTML输出中显示,在每个 <th> 元素上以 column-<field_name> 的形式。例如,这可以用于在CSS文件中设置列宽。

  • Django将尝试按照以下顺序解释 list_display 的每个元素:

    • 模型的一个字段。

    • 一个callable。

    • 表示 ModelAdmin 属性的字符串。

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

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

使用 list_display_links 来控制是否以及 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 以激活管理员更改列表页面右侧边栏中的过滤器,如以下屏幕截图所示:

../../../_images/list_filter.png

list_filter 应该是一个元素的列表或元组,其中每个元素应该是以下类型之一:

  • 字段名称,其中指定的字段应该是 BooleanFieldCharFieldDateFieldDateTimeFieldIntegerFieldForeignKeyManyToManyField,例如:

    class PersonAdmin(admin.ModelAdmin):
        list_filter = ('is_staff', 'company')
    

    例如,list_filter 中的字段名称也可以跨越使用 __ 查找的关系:

    class PersonAdmin(admin.UserAdmin):
        list_filter = ('company__name',)
    
  • django.contrib.admin.SimpleListFilter 继承的类,您需要提供 titleparameter_name 属性并覆盖 lookupsqueryset 方法,例如。:

    from datetime import date
    
    from django.contrib import admin
    from django.utils.translation import ugettext_lazy as _
    
    class DecadeBornListFilter(admin.SimpleListFilter):
        # Human-readable title which will be displayed in the
        # right admin sidebar just above the filter options.
        title = _('decade born')
    
        # Parameter for the filter that will be used in the URL query.
        parameter_name = 'decade'
    
        def lookups(self, request, model_admin):
            """
            Returns a list of tuples. The first element in each
            tuple is the coded value for the option that will
            appear in the URL query. The second element is the
            human-readable name for the option that will appear
            in the right sidebar.
            """
            return (
                ('80s', _('in the eighties')),
                ('90s', _('in the nineties')),
            )
    
        def queryset(self, request, queryset):
            """
            Returns the filtered queryset based on the value
            provided in the query string and retrievable via
            `self.value()`.
            """
            # Compare the requested value (either '80s' or '90s')
            # to decide how to filter the queryset.
            if self.value() == '80s':
                return queryset.filter(birthday__gte=date(1980, 1, 1),
                                        birthday__lte=date(1989, 12, 31))
            if self.value() == '90s':
                return queryset.filter(birthday__gte=date(1990, 1, 1),
                                        birthday__lte=date(1999, 12, 31))
    
    class PersonAdmin(admin.ModelAdmin):
        list_filter = (DecadeBornListFilter,)
    

    注解

    为了方便起见,HttpRequest 对象被传递给例如 lookupsqueryset 方法:

    class AuthDecadeBornListFilter(DecadeBornListFilter):
    
        def lookups(self, request, model_admin):
            if request.user.is_superuser:
                return super(AuthDecadeBornListFilter, self).lookups(request, model_admin)
    
        def queryset(self, request, queryset):
            if request.user.is_superuser:
                return super(AuthDecadeBornListFilter, self).queryset(request, queryset)
    

    另外,为了方便起见,ModelAdmin 对象被传递给 lookups 方法,例如,如果您希望查找可用数据:

    class AdvancedDecadeBornListFilter(DecadeBornListFilter):
    
        def lookups(self, request, model_admin):
            """
            Only show the lookups if there actually is
            anyone born in the corresponding decades.
            """
            qs = model_admin.get_queryset(request)
            if qs.filter(birthday__gte=date(1980, 1, 1),
                          birthday__lte=date(1989, 12, 31)).exists():
                yield ('80s', _('in the eighties'))
            if qs.filter(birthday__gte=date(1990, 1, 1),
                          birthday__lte=date(1999, 12, 31)).exists():
                yield ('90s', _('in the nineties'))
    
  • 例如,元组,其中第一元素是字段名称,第二元素是从 django.contrib.admin.FieldListFilter 继承的类:

    class PersonAdmin(admin.ModelAdmin):
        list_filter = (
            ('is_staff', admin.BooleanFieldListFilter),
        )
    

    您可以使用 RelatedOnlyFieldListFilter 将相关模型的选择限制为该关系中涉及的对象:

    class BookAdmin(admin.ModelAdmin):
        list_filter = (
            ('author', admin.RelatedOnlyFieldListFilter),
        )
    

    假设 authorUser 模型的 ForeignKey,这将限制 list_filter 选择给已经编写书而不是列出所有用户的用户。

    注解

    FieldListFilter API被视为内部,可能会更改。

列表过滤器通常仅在过滤器有多个选项时出现。过滤器的 has_output() 方法控制是否出现。

可以指定用于呈现列表过滤器的自定义模板:

class FilterWithCustomTemplate(admin.SimpleListFilter):
    template = "custom_template.html"

有关具体示例,请参阅Django(admin/filter.html)提供的默认模板。

ModelAdmin.list_max_show_all

设置 list_max_show_all 以控制在“显示所有”管理更改列表页面上可以显示多少项目。只有当总结果计数小于或等于此设置时,管理员才会在更改列表上显示“显示全部”链接。默认情况下,它设置为 200

ModelAdmin.list_per_page

设置 list_per_page 以控制在每个分页的管理更改列表页面上显示的项目数。默认情况下,它设置为 100

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

该值应该是布尔值,列表或元组。默认为 False

当值为 True 时,select_related() 将始终被调用。当值设置为 False 时,Django将查看 list_display 并调用 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.ordering

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

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

如果需要指定动态顺序(例如,根据用户或语言),您可以实施 get_ordering() 方法。

ModelAdmin.paginator

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 字段的值。生成的值是通过连接源字段的值,然后将该结果转换为有效的字节(例如用空格替换破折号)来生成的。

prepopulated_fields 不接受 DateTimeFieldForeignKeyManyToManyField 字段。

ModelAdmin.preserve_filters

管理员现在在创建,编辑或删除对象后保留列表视图中的过滤器。通过将此属性设置为 False,可以恢复以前清除过滤器的行为。

ModelAdmin.radio_fields

默认情况下,Django的管理员对于 ForeignKey 或设置了 choices 的字段使用选择框接口(<select>)。如果 radio_fields 中存在字段,Django将使用单选按钮接口。假设 groupPerson 模型上的 ForeignKey:

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

您可以选择使用 django.contrib.admin 模块中的 HORIZONTALVERTICAL

不要在 radio_fields 中包含字段,除非它是 ForeignKey 或具有 choices 集。

ModelAdmin.raw_id_fields

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

raw_id_fields 是您要更改为 ForeignKeyManyToManyFieldInput 窗口小部件的字段列表:

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

如果字段是 ForeignKey,则 raw_id_fields Input 小部件应包含主键,如果字段是 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',)

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

    # short_description functions like a model field's verbose_name
    address_report.short_description = "Address"
ModelAdmin.save_as

设置 save_as 以启用管理员更改表单上的“另存为新功能”功能。

通常,对象有三个保存选项:“保存”,“保存并继续编辑”和“保存并添加另一个”。如果 save_asTrue,则“保存并添加另一个”将替换为创建新对象(具有新ID)而不是更新现有对象的“另存为新”按钮。

默认情况下,save_as 设置为 False

ModelAdmin.save_as_continue
New in Django 1.10.

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。您还可以使用查找API“跟随”符号在 ForeignKeyManyToManyField 上执行相关查找:

search_fields = ['foreign_key__related_fieldname']

例如,如果您有一个作者的博客条目,以下定义将允许通过作者的电子邮件地址搜索博客条目:

search_fields = ['user__email']

当有人在管理搜索框中进行搜索时,Django将搜索查询分割成单词,并返回包含每个单词的所有对象,不区分大小写,其中每个单词必须至少包含一个 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%')

对于更快和/或更严格的搜索,请在字段名称前加上运算符:

^

使用“^”运算符匹配从字段开始处开始。例如,如果 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%' 查询更有效,因为数据库只需检查列的数据的开头,而不是遍历整个列的数据。此外,如果列上有索引,某些数据库可能能够使用该查询的索引,即使它是 LIKE 查询。

=

对不区分大小写的完全匹配使用’=’运算符。例如,如果 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')

请注意,查询输入由空格拆分,因此,在此示例之后,当前无法搜索其中 first_name 正确为 'john winston' (包含空格)的所有记录。

@

使用“@”运算符执行全文匹配。这类似于默认搜索方法,但使用索引。目前这只能用于MySQL。

如果您需要自定义搜索,您可以使用 ModelAdmin.get_search_results() 提供其他或备用搜索行为。

ModelAdmin.show_full_result_count

设置 show_full_result_count 以控制是否应在过滤的管理页面(例如 99 results (103 total))上显示对象的完整计数。如果此选项设置为 False,则会显示类似 99 results (Show all) 的文本。

show_full_result_count=True 的默认值会生成一个查询,对表执行完全计数,如果表包含大量行,这可能很昂贵。

ModelAdmin.view_on_site

设置 view_on_site 以控制是否显示“在网站上查看”链接。此链接将带您到一个URL,您可以在其中显示已保存的对象。

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

如果您的模型具有 get_absolute_url() 方法,但您不想显示“在网站上查看”按钮,您只需要将 view_on_site 设置为 False:

from django.contrib import admin

class PersonAdmin(admin.ModelAdmin):
    view_on_site = False

如果它是可调用的,它接受模型实例作为参数。例如:

from django.contrib import admin
from django.urls import reverse

class PersonAdmin(admin.ModelAdmin):
    def view_on_site(self, obj):
        url = reverse('person-detail', kwargs={'slug': obj.slug})
        return 'https://example.com' + url

自定义模板选项

覆盖管理模板 部分描述如何覆盖或扩展默认管理模板。使用以下选项覆盖 ModelAdmin 视图使用的默认模板:

ModelAdmin.add_form_template

add_view() 使用的自定义模板的路径。

ModelAdmin.change_form_template

change_view() 使用的自定义模板的路径。

ModelAdmin.change_list_template

changelist_view() 使用的自定义模板的路径。

ModelAdmin.delete_confirmation_template

自定义模板的路径,由 delete_view() 用于在删除一个或多个对象时显示确认页面。

ModelAdmin.delete_selected_confirmation_template

自定义模板的路径,由 delete_selected 操作方法用于在删除一个或多个对象时显示确认页面。见 actions documentation

ModelAdmin.object_history_template

history_view() 使用的自定义模板的路径。

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(ArticleAdmin, self).save_model(request, obj, form, change)
ModelAdmin.delete_model(request, obj)

delete_model 方法给出了 HttpRequest 和模型实例。覆盖此方法允许执行删除前或删除后操作。调用 super().delete_model() 使用 Model.delete() 删除对象。

ModelAdmin.save_formset(request, form, formset, change)

save_formset 方法被给予 HttpRequest,父 ModelForm 实例和基于是否添加或更改父对象的布尔值。

例如,将 request.user 附加到每个已更改的formset模型实例:

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

参见 将对象保存在formset中

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 中命名的字段。

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

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

class PersonAdmin(admin.ModelAdmin):
    list_display = ('name', 'age')
    search_fields = ('name',)

    def get_search_results(self, request, queryset, search_term):
        queryset, use_distinct = super(PersonAdmin, self).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, use_distinct

这种实现比 search_fields = ('name', '=age') 更有效,其导致数字字段的字符串比较,例如PostgreSQL上的 ... OR UPPER("polls_choice"."votes"::text) = UPPER('4')

save_related 方法被给予 HttpRequest,父 ModelForm 实例,内联表单的列表和基于父是否被添加或改变的布尔值。在这里,您可以对与父级相关的对象执行任何预保存或后保存操作。请注意,此时,父对象及其形式已保存。

ModelAdmin.get_readonly_fields(request, obj=None)

get_readonly_fields 方法被给予 HttpRequestobj 被编辑(或者在添加表单上的 None),并且期望返回将被显示为只读的字段名称的 listtuple,如上面在 ModelAdmin.readonly_fields 部分中所描述的。

ModelAdmin.get_prepopulated_fields(request, obj=None)

get_prepopulated_fields 方法被给予 HttpRequestobj 被编辑(或者在添加形式上的 None),并且期望返回 dictionary,如上面在 ModelAdmin.prepopulated_fields 部分中所描述的。

ModelAdmin.get_list_display(request)

get_list_display 方法被给予 HttpRequest,并且期望返回字段名称的 listtuple,这将在如上所述的 ModelAdmin.list_display 部分中显示在更改列表视图上。

get_list_display_links 方法给出 HttpRequestlisttupleModelAdmin.get_list_display() 返回。它希望返回 None 或更改列表上将链接到更改视图的字段名称的 listtuple,如 ModelAdmin.list_display_links 部分中所述。

ModelAdmin.get_fields(request, obj=None)

get_fields 方法被给予 HttpRequestobj 被编辑(或者在添加表单上的 None),并且期望返回字段列表,如上面在 ModelAdmin.fields 部分中所描述的。

ModelAdmin.get_fieldsets(request, obj=None)

get_fieldsets 方法被给予 HttpRequestobj 被编辑(或者在添加表单上的 None),并且期望返回两元组的列表,其中每个二元组表示管理表单页面上的 <fieldset>,如上所述在 ModelAdmin.fieldsets 部分。

ModelAdmin.get_list_filter(request)

get_list_filter 方法被给予 HttpRequest,并且期望返回与 list_filter 属性相同类型的序列类型。

New in Django 1.9.

get_list_select_related 方法被赋予 HttpRequest,并且应该返回布尔或列表作为 ModelAdmin.list_select_related

ModelAdmin.get_search_fields(request)

get_search_fields 方法被给予 HttpRequest,并且期望返回与 search_fields 属性相同类型的序列类型。

ModelAdmin.get_inline_instances(request, obj=None)

get_inline_instances 方法被给予 HttpRequestobj 被编辑(或者在添加形式上的 None),并且期望返回 InlineModelAdmin 对象的 listtuple,如下面在 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_urls()

ModelAdmin 上的 get_urls 方法以与URLconf相同的方式返回用于该ModelAdmin的URL。因此,您可以按照 网址调度员 中所述扩展它们:

class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(MyModelAdmin, self).get_urls()
        my_urls = [
            url(r'^my_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 %}

注解

请注意,自定义模式包含在 before 常规管理网址中:管理网址模式是非常宽松的,几乎可以匹配任何内容,因此您通常会想要将自定义网址添加到内置网址。

在这个例子中,my_view 将在 /admin/myapp/mymodel/my_view/ 被访问(假设管理URL被包括在 /admin/。)

然而,上面注册的 self.my_view 功能存在两个问题:

  • 它将 not 执行任何权限检查,所以它将是公众可以访问的。

  • 它将 not 提供任何头信息以防止缓存。这意味着如果页面从数据库检索数据,并且缓存中间件是活动的,页面可能显示过时的信息。

因为这通常不是你想要的,Django提供了一个方便的包装检查权限,并将视图标记为不可缓存。这个包装器是 AdminSite.admin_view() (即 ModelAdmin 实例内的 self.admin_site.admin_view);使用它像这样:

class MyModelAdmin(admin.ModelAdmin):
    def get_urls(self):
        urls = super(MyModelAdmin, self).get_urls()
        my_urls = [
            url(r'^my_view/$', self.admin_site.admin_view(self.my_view))
        ]
        return my_urls + urls

请注意上面第五行中的包装视图:

url(r'^my_view/$', self.admin_site.admin_view(self.my_view))

这种包装将保护 self.my_view 免受未经授权的访问,并将应用 django.views.decorators.cache.never_cache() 装饰器以确保如果高速缓存中间件是活动的,它不被高速缓存。

如果页面可缓存,但您仍希望执行权限检查,则可以将 cacheable=True 参数传递给 AdminSite.admin_view():

url(r'^my_view/$', self.admin_site.admin_view(self.my_view, cacheable=True))
New in Django 1.9.

ModelAdmin 视图有 model_admin 属性。其他 AdminSite 视图有 admin_site 属性。

ModelAdmin.get_form(request, obj=None, **kwargs)

返回用于管理添加和更改视图的 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(MyModelAdmin, self).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 isinstance(inline, MyInline) and obj is None:
                continue
            yield inline.get_formset(request, obj), inline
ModelAdmin.formfield_for_foreignkey(db_field, request, **kwargs)

ModelAdmin 上的 formfield_for_foreignkey 方法允许您覆盖外键字段的默认窗体字段。例如,基于用户返回此外键字段的对象子集:

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_foreignkey(self, db_field, request, **kwargs):
        if db_field.name == "car":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
        return super(MyModelAdmin, self).formfield_for_foreignkey(db_field, request, **kwargs)

这使用 HttpRequest 实例过滤 Car 外键字段,以仅显示 User 实例所拥有的汽车。

ModelAdmin.formfield_for_manytomany(db_field, request, **kwargs)

formfield_for_foreignkey 方法类似,formfield_for_manytomany 方法可以被覆盖以更改多对多字段的默认形式字段。例如,如果所有者可以拥有多个汽车,并且汽车可以属于多个所有者 - 多对多关系 - 您可以过滤 Car 外键字段以仅显示 User 拥有的汽车:

class MyModelAdmin(admin.ModelAdmin):
    def formfield_for_manytomany(self, db_field, request, **kwargs):
        if db_field.name == "cars":
            kwargs["queryset"] = Car.objects.filter(owner=request.user)
        return super(MyModelAdmin, self).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 方法以更改已声明选择的字段的默认窗体字段。例如,如果超级用户可用的选择应与正式工作人员可用的选项不同,则可按以下步骤操作:

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'] += (('ready', 'Ready for deployment'),)
        return super(MyModelAdmin, self).formfield_for_choice_field(db_field, request, **kwargs)

注意

在formfield上设置的任何 choices 属性将仅限于表单字段。如果模型上的相应字段具有选项集,则提供给表单的选项必须是这些选项的有效子集,否则,在保存之前验证模型本身时,表单提交将失败,有 ValidationError

ModelAdmin.get_changelist(request, **kwargs)

返回要用于列出的 Changelist 类。默认情况下,使用 django.contrib.admin.views.main.ChangeList。通过继承此类,您可以更改列表的行为。

ModelAdmin.get_changelist_form(request, **kwargs)

返回在更改列表页面上的 Formset 中使用的 ModelForm 类。例如,要使用自定义窗体:

from django import forms

class MyForm(forms.ModelForm):
    pass

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

注意

如果在 ModelForm 上定义 Meta.model 属性,则还必须定义 Meta.fields 属性(或 Meta.exclude 属性)。但是,ModelAdmin 忽略此值,使用 ModelAdmin.list_editable 属性覆盖它。最简单的解决方案是省略 Meta.model 属性,因为 ModelAdmin 将提供正确的模型来使用。

ModelAdmin.get_changelist_formset(request, **kwargs)

如果使用 list_editable,则返回 ModelFormSet 类以在更改列表页上使用。例如,要使用自定义表单集:

from django.forms import BaseModelFormSet

class MyAdminFormSet(BaseModelFormSet):
    pass

class MyModelAdmin(admin.ModelAdmin):
    def get_changelist_formset(self, request, **kwargs):
        kwargs['formset'] = MyAdminFormSet
        return super(MyModelAdmin, self).get_changelist_formset(request, **kwargs)
ModelAdmin.has_add_permission(request)

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

ModelAdmin.has_change_permission(request, obj=None)

如果允许编辑obj,则返回 True,否则返回 False。如果obj是 None,则应该返回 TrueFalse 以指示是否允许对这种类型的对象的编辑(例如,False 将被解释为意味着当前用户不允许编辑此类型的任何对象)。

ModelAdmin.has_delete_permission(request, obj=None)

如果允许删除obj,应返回 True,否则返回 False。如果obj是 None,则应该返回 TrueFalse 以指示是否允许删除这种类型的对象(例如,False 将被解释为意味着当前用户不允许删除该类型的任何对象)。

ModelAdmin.has_module_permission(request)

如果在管理索引页上显示模块并且允许访问模块的索引页,则应返回 True,否则为 False。默认使用 User.has_module_perms()。覆盖它不限制对添加,更改或删除视图的访问,应使用 has_add_permission()has_change_permission()has_delete_permission()

ModelAdmin.get_queryset(request)

ModelAdmin 上的 get_queryset 方法返回管理站点可以编辑的所有模型实例的 QuerySet。覆盖此方法的一个用例是显示由登录用户拥有的对象:

class MyModelAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super(MyModelAdmin, self).get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(author=request.user)
ModelAdmin.message_user(request, message, level=messages.INFO, extra_tags='', fail_silently=False)

使用 django.contrib.messages 后端向用户发送消息。见 自定义ModelAdmin示例

关键字参数允许您更改消息级别,添加额外的CSS标签,或者如果未安装 contrib.messages 框架,则默认失败。这些关键字参数与 django.contrib.messages.add_message() 的参数匹配,有关更多详细信息,请参阅该函数的文档。一个区别是,除了整数/常数之外,级别可以作为字符串标签传递。

ModelAdmin.get_paginator(request, queryset, per_page, orphans=0, allow_empty_first_page=True)

返回要用于此视图的分页的实例。默认情况下,实例化 paginator 的实例。

ModelAdmin.response_add(request, obj, post_url_continue=None)

确定 add_view() 阶段的 HttpResponse

response_add 在管理表单提交后,在对象和所有相关实例创建并保存后被调用。您可以覆盖它以更改对象创建后的默认行为。

ModelAdmin.response_change(request, obj)

确定 change_view() 阶段的 HttpResponse

response_change 在管理表单提交后并在对象和所有相关实例都保存后调用。您可以覆盖它以更改对象后更改默认行为。

ModelAdmin.response_delete(request, obj_display, obj_id)

确定 delete_view() 阶段的 HttpResponse

在对象被删除后调用 response_delete。您可以覆盖它以在对象被删除后更改默认行为。

obj_display 是具有已删除对象名称的字符串。

obj_id 是用于检索要删除的对象的序列化标识符。

ModelAdmin.get_changeform_initial_data(request)

用于管理员更改表单上的初始数据的挂钩。默认情况下,字段从 GET 参数给定初始值。例如,?name=initial_valuename 字段的初始值设置为 initial_value

此方法应返回 {'fieldname': 'fieldval'} 形式的字典:

def get_changeform_initial_data(self, request):
    return {'name': 'custom_initial_value'}

其他方法

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(MyModelAdmin, self).change_view(
            request, object_id, form_url, extra_context=extra_context,
        )

这些视图返回 TemplateResponse 实例,允许您在渲染之前轻松自定义响应数据。有关详细信息,请参阅 TemplateResponse文档

ModelAdmin 资产定义

有时你想添加一些CSS和/或JavaScript到添加/更改视图。这可以通过在您的 ModelAdmin 上使用 Media 内部类来实现:

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

staticfiles应用程序 预先考虑 STATIC_URL (或 MEDIA_URL 如果 STATIC_URLNone),以任何资产路径。相同的规则适用于 表格上的常规资产定义

jQuery

Django管理JavaScript利用 jQuery 库。

为了避免与用户提供的脚本或库冲突,Django的jQuery(版本2.2.3)命名为 django.jQuery。如果要在自己的管理JavaScript中使用jQuery而不包括第二个副本,则可以在changelist上使用 django.jQuery 对象并添加/编辑视图。

Changed in Django 1.9:

嵌入的jQuery从1.11.2升级到2.1.4。这将下降对Internet Explorer 8及以下版本的支持。您可以通过 包括你自己的jQuery 1.X版本 恢复支持。

Changed in Django 1.10:

嵌入的jQuery从2.1.4升级到2.2.3。

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

Django提供了jQuery的uncompressed和’minified’版本,分别为 jquery.jsjquery.min.js

ModelAdminInlineModelAdmin 具有返回一个 Media 对象列表的 media 属性,这些对象存储表单和/或formets的JavaScript文件的路径。如果 DEBUGTrue,它将返回各种JavaScript文件的未压缩版本,包括 jquery.js;如果没有,它将返回“minified”版本。

向管理员添加自定义验证

在管理员中添加数据的自定义验证是很容易的。自动管理界面重用 django.formsModelAdmin 类为您提供定义自己形式的能力:

class ArticleAdmin(admin.ModelAdmin):
    form = MyArticleAdminForm

MyArticleAdminForm 可以在任何地方定义,只要您在需要时导入即可。现在在您的表单中,您可以为任何字段添加自己的自定义验证:

class MyArticleAdminForm(forms.ModelForm):
    def clean_name(self):
        # do something that validates your data
        return self.cleaned_data["name"]

重要的是你在这里使用 ModelForm 否则会破坏。有关详细信息,请参阅 自定义验证形式 文档,更具体地,模型表单验证注释

InlineModelAdmin 对象

class InlineModelAdmin
class TabularInline
class StackedInline

管理界面能够在与父模型相同的页面上编辑模型。这些称为内联。假设你有这两个模型:

from django.db import models

class Author(models.Model):
   name = models.CharField(max_length=100)

class Book(models.Model):
   author = models.ForeignKey(Author, on_delete=models.CASCADE)
   title = models.CharField(max_length=100)

您可以在作者页面上编辑作者创作的书籍。通过在 ModelAdmin.inlines 中指定模型,可以向模型添加内联:

from django.contrib import admin

class BookInline(admin.TabularInline):
    model = Book

class AuthorAdmin(admin.ModelAdmin):
    inlines = [
        BookInline,
    ]

Django提供了 InlineModelAdmin 的两个子类,它们是:

这两者之间的区别仅仅是用于渲染它们的模板。

InlineModelAdmin 选项

InlineModelAdminModelAdmin 具有许多相同的功能,并添加了一些自己的功能(共享特性实际上是在 BaseModelAdmin 超类中定义的)。共享功能包括:

InlineModelAdmin 类添加:

InlineModelAdmin.model

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

InlineModelAdmin.fk_name

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

InlineModelAdmin.formset

此默认值为 BaseInlineFormSet。使用自己的表单可以给你很多自定义的可能性。内联围绕 模型formets 构建。

InlineModelAdmin.form

form 的值默认为 ModelForm。这是在为此内联创建表单集时传递给 inlineformset_factory() 的内容。

警告

在为 InlineModelAdmin 表单编写自定义验证时,请谨慎编写依赖父模型功能的验证。如果父模型未能验证,则可能会处于不一致状态,如 验证 ModelForm 中的警告中所述。

InlineModelAdmin.classes
New in Django 1.10.

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

InlineModelAdmin.extra

这控制除初始形式外,表单集将显示的额外表单的数量。有关详细信息,请参阅 formets文档

对于具有启用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的管理员为 ForeignKey 的字段使用选择框接口(<select>)。有时,您不希望产生必须选择要在下拉列表中显示的所有相关实例的开销。

raw_id_fields 是您要更改为 ForeignKeyManyToManyFieldInput 窗口小部件的字段列表:

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

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

InlineModelAdmin.verbose_name

在模型的内部 Meta 类中找到的 verbose_name 的覆盖。

InlineModelAdmin.verbose_name_plural

在模型的内部 Meta 类中找到的 verbose_name_plural 的覆盖。

InlineModelAdmin.can_delete

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

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

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

返回用于管理员添加/更改视图的 BaseInlineFormSet 类。参见 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 传递)。

使用具有两个或多个外键的模型到同一个父模型

有时可能有多个外键到同一个模型。拿这个模型为例:

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 定义,模型中的每个many-to-many字段将由标准HTML <select multiple>,水平或垂直过滤器或 raw_id_admin 窗口小部件表示。然而,也可以用内联替换这些小部件。

假设我们有以下模型:

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.throughthrough 属性是对管理多对多关系的模型的引用。在定义多对多字段时,此模型由Django自动创建。

其次,GroupAdmin 必须手动排除 members 字段。 Django在定义关系的模型上显示多对多字段的管理窗口小部件(在本例中为 Group)。如果要使用内联模型来表示多对多关系,则必须告诉Django的管理员 not 显示此窗口小部件 - 否则您将在管理页面上最终得到两个窗口小部件,用于管理关系。

注意,当使用这种技术时,m2m_changed 信号不被触发。这是因为就管理员而言,through 只是一个具有两个外键字段而不是多对多关系的模型。

在所有其他方面,InlineModelAdmin 与任何其他方面完全相同。您可以使用任何正常的 ModelAdmin 属性自定义外观。

使用多对多中介模型

当您使用 ManyToManyFieldthrough 参数指定中介模型时,默认情况下,管理员不会显示窗口小部件。这是因为该中间模型的每个实例需要比可以在单个小部件中显示的更多的信息,并且多个小部件所需的布局将根据中间模型而变化。

但是,我们仍然希望能够内联编辑该信息。幸运的是,这很容易与内联管理模型。假设我们有以下模型:

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=128)

class Group(models.Model):
    name = models.CharField(max_length=128)
    members = models.ManyToManyField(Person, through='Membership')

class Membership(models.Model):
    person = models.ForeignKey(Person, on_delete=models.CASCADE)
    group = models.ForeignKey(Group, on_delete=models.CASCADE)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

在管理中显示此中间模型的第一步是为 Membership 模型定义一个内联类:

class MembershipInline(admin.TabularInline):
    model = Membership
    extra = 1

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

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

class PersonAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

class GroupAdmin(admin.ModelAdmin):
    inlines = (MembershipInline,)

最后,使用管理网站注册您的 PersonGroup 型号:

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

现在您的管理网站已设置为从 PersonGroup 详细信息页面内联编辑 Membership 对象。

使用泛型关系作为内联

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

from django.db import models
from django.contrib.contenttypes.fields import GenericForeignKey

class Image(models.Model):
    image = models.ImageField(upload_to="images")
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey("content_type", "object_id")

class Product(models.Model):
    name = models.CharField(max_length=100)

如果要允许在 Product 上编辑和创建 Image 实例,可以添加/更改视图,您可以使用 admin 提供的 GenericTabularInlineGenericStackedInline (两个子类 GenericInlineModelAdmin)。它们分别为表示内联对象的表单实现表格和堆叠的可视布局,就像它们的非类属对象一样。他们的行为就像任何其他内联。在您的 admin.py 此示例应用程序:

from django.contrib import admin
from django.contrib.contenttypes.admin import GenericTabularInline

from myproject.myapp.models import Image, Product

class ImageInline(GenericTabularInline):
    model = Image

class ProductAdmin(admin.ModelAdmin):
    inlines = [
        ImageInline,
    ]

admin.site.register(Product, ProductAdmin)

有关更多具体信息,请参阅 contenttypes文档

覆盖管理模板

覆盖管理模块用来生成管理站点的各种页面的许多模板是相对容易的。您甚至可以覆盖特定应用程序或特定模型的这些模板中的几个。

设置项目管理模板目录

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

为了覆盖其中一个或多个,首先在项目的 templates 目录中创建一个 admin 目录。这可以是您在 TEMPLATES 设置中在 DjangoTemplates 后端的 DIRS 选项中指定的任何目录。如果您已经定制了 'loaders' 选项,请确保在 'django.template.loaders.app_directories.Loader' 之前显示 'django.template.loaders.filesystem.Loader',以便在 django.contrib.admin 附带的模板加载系统之前找到您的自定义模板。

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

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

例如,如果我们要为名为 my_app 的应用程序中的所有模型向更改列表视图添加一个工具,我们将复制 contrib/admin/templates/admin/change_list.html 到我们项目的 templates/admin/my_app/ 目录,并进行任何必要的更改。

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

覆盖与替换管理模板

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

要继续上面的示例,我们要为 Page 模型的 History 工具旁边添加一个新链接。看了 change_form.html 后,我们确定我们只需要覆盖 object-tools-items 块。因此这里是我们的新 change_form.html

{% extends "admin/change_form.html" %}
{% load i18n admin_urls %}
{% block object-tools-items %}
    <li>
        <a href="{% url opts|admin_urlname:'history' original.pk|admin_urlquote %}" class="historylink">{% trans "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">{% trans "View on site" %}</a>
        </li>
    {% endif %}
{% endblock %}

就是这样!如果我们将此文件放在 templates/admin/my_app 目录中,我们的链接将出现在my_app中所有模型的更改表单上。

可以针对每个应用或模型覆盖的模板

不是每个应用程序或每个模型都覆盖 contrib/admin/templates/admin 中的每个模板。以下可以:

  • app_index.html

  • change_form.html

  • change_list.html

  • delete_confirmation.html

  • object_history.html

对于那些不能以这种方式覆盖的模板,您仍然可以为整个项目覆盖它们。只需将新版本放在您的 templates/admin 目录中。这对创建自定义404和500页特别有用。

注解

某些管理模板(如 change_list_results.html)用于呈现自定义包含标记。这些可能被覆盖,但在这种情况下,你可能更好地创建自己的版本的标签,并给它一个不同的名称。这样你可以选择性地使用它。

根和登录模板

如果要更改索引,登录或注销模板,最好创建自己的 AdminSite 实例(请参见下文),并更改 AdminSite.index_templateAdminSite.login_templateAdminSite.logout_template 属性。

AdminSite 对象

class AdminSite(name='admin')

Django管理站点由 django.contrib.admin.sites.AdminSite 的实例表示;默认情况下,此类的实例将创建为 django.contrib.admin.site,您可以使用它注册您的模型和 ModelAdmin 实例。

当构建 AdminSite 的实例时,您可以使用构造函数的 name 参数提供唯一的实例名称。此实例名称用于标识实例,特别是在 反转管理URL 时。如果没有提供实例名称,将使用 admin 的默认实例名称。有关自定义 AdminSite 类的示例,请参阅 自定义 AdminSite 类

AdminSite 属性

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

AdminSite.site_header

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

AdminSite.site_title

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

AdminSite.site_url

每个管理页面顶部的“查看网站”链接的网址。默认情况下,site_url/。将其设置为 None 以删除链接。

对于在子路径上运行的站点,each_context() 方法检查当前请求是否设置了 request.META['SCRIPT_NAME'],如果 site_url 未设置为 / 之外的值,则使用该值。

Changed in Django 1.10:

增加了上一段所述的 SCRIPT_NAME 支持。

AdminSite.index_title

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

AdminSite.index_template

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

AdminSite.app_index_template

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

AdminSite.empty_value_display
New in Django 1.9.

用于在管理网站的更改列表中显示空值的字符串。默认为破折号。还可以通过在字段上设置 empty_value_display 属性,在每个 ModelAdmin 基础上以及 ModelAdmin 中的自定义字段上覆盖该值。参见 ModelAdmin.empty_value_display 的例子。

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_headerAdminSite.site_header

  • site_titleAdminSite.site_title

  • site_urlAdminSite.site_url

  • has_permissionAdminSite.has_permission()

  • available_apps应用程序注册表 中可用于当前用户的应用程序列表。列表中的每个条目都是使用以下键表示应用程序的dict:

    • app_label:应用程序标签

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

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

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

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

    • object_name:模型的类名

    • name:模型的复数名称

    • permsdict 跟踪 addchangedelete 权限

    • admin_url:模型的admin更改列表URL

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

Changed in Django 1.9:

添加 available_apps 变量。

AdminSite.has_permission(request)

如果给定 HttpRequest 的用户有权查看管理网站中的至少一个页面,则返回 True。默认为要求 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.sites.AlreadyRegistered

AdminSite 实例挂接到您的URLconf中

设置Django管理员的最后一步是将您的 AdminSite 实例挂接到您的URLconf。通过指定给定的URL在 AdminSite.urls 方法来做到这一点。没有必要使用 include()

在这个例子中,我们在URL /admin/ 注册默认的 AdminSite 实例 django.contrib.admin.site

# urls.py
from django.conf.urls import url
from django.contrib import admin

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]
Changed in Django 1.9:

在以前的版本中,您将 admin.site.urls 传递给 include()

自定义 AdminSite

如果你想设置你自己的管理网站的自定义行为,你可以自由地子类 AdminSite,覆盖或添加任何你喜欢的。然后,只需创建一个 AdminSite 子类的实例(与您实例化任何其他Python类相同),并注册您的模型和 ModelAdmin 子类,而不是使用默认网站。最后,更新 myproject/urls.py 以引用您的 AdminSite 子类。

myapp/admin.py
from django.contrib.admin import AdminSite

from .models import MyModel

class MyAdminSite(AdminSite):
    site_header = 'Monty Python administration'

admin_site = MyAdminSite(name='myadmin')
admin_site.register(MyModel)
myproject/urls.py
from django.conf.urls import url

from myapp.admin import admin_site

urlpatterns = [
    url(r'^myadmin/', admin_site.urls),
]

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

在同一个URLconf中有多个管理网站

在同一个Django供电的网站上轻松创建管理网站的多个实例。只需创建多个 AdminSite 实例,并将每个实例都在不同的URL。

在此示例中,URL /basic-admin//advanced-admin/ 分别具有管理站点的版本 - 分别使用 AdminSite 实例 myproject.admin.basic_sitemyproject.admin.advanced_site:

# urls.py
from django.conf.urls import url
from myproject.admin import basic_site, advanced_site

urlpatterns = [
    url(r'^basic-admin/', basic_site.urls),
    url(r'^advanced-admin/', advanced_site.urls),
]

AdminSite 实例对它们的构造函数采用单个参数,它们的名称可以是任何你喜欢的。此参数成为用于 reversing them 的URL名称的前缀。这只有在您使用多个 AdminSite 时才需要。

向管理网站添加视图

ModelAdmin 一样,AdminSite 提供了一个 get_urls() 方法,可以覆盖此方法以定义网站的其他视图。要向您的管理网站添加新视图,请扩展基本 get_urls() 方法以包含新视图的模式。

注解

您渲染的任何使用管理模板的视图,或扩展基本管理模板,应在渲染模板之前设置 request.current_app。如果您的视图在 AdminSite 上,则应将其设置为 self.name,如果您的视图是 ModelAdmin,则应将其设置为 self.admin_site.name

添加密码重置功能

您可以通过向URLconf中添加几行来向管理站点添加密码重置功能。具体来说,添加这四个模式:

from django.contrib.auth import views as auth_views

url(r'^admin/password_reset/$', auth_views.password_reset, name='admin_password_reset'),
url(r'^admin/password_reset/done/$', auth_views.password_reset_done, name='password_reset_done'),
url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$', auth_views.password_reset_confirm, name='password_reset_confirm'),
url(r'^reset/done/$', auth_views.password_reset_complete, name='password_reset_complete'),

(假设您已在 admin/ 添加管理员,并要求您将包含管理应用程序本身的行之前的URL以 ^admin/ 开头)。

admin_password_reset 命名的URL的存在将导致“忘记你的密码?链接出现在默认管理登录页面的密码框下。

LogEntry 对象

class models.LogEntry

LogEntry 类跟踪通过管理界面完成的对象的添加,更改和删除。

LogEntry 属性

LogEntry.action_time

操作的日期和时间。

LogEntry.user

执行操作的用户(AUTH_USER_MODEL 实例)。

LogEntry.content_type

修改对象的 ContentType

LogEntry.object_id

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

LogEntry.object_repr

修改后的对象的 repr()

LogEntry.action_flag

记录的操作类型:ADDITIONCHANGEDELETION

例如,获取通过管理员完成的所有添加的列表:

from django.contrib.admin.models import LogEntry, ADDITION

LogEntry.objects.filter(action_flag=ADDITION)
LogEntry.change_message

修改的详细描述。例如,在编辑的情况下,消息包含编辑的字段的列表。 Django管理网站将此内容格式化为JSON结构,以便 get_change_message() 可以重组按当前用户语言翻译的消息。自定义代码可能会将其设置为纯字符串。建议您使用 get_change_message() 方法检索此值,而不是直接访问它。

Changed in Django 1.10:

以前,此属性始终是纯字符串。它现在是JSON结构,以便消息可以翻译当前用户语言。旧消息不受影响。

LogEntry 方法

LogEntry.get_edited_object()

返回引用对象的快捷方式。

LogEntry.get_change_message()
New in Django 1.10.

格式化并将 change_message 转换为当前用户语言。在Django 1.10之前创建的消息将始终以它们被记录的语言显示。

还原管理网址

当部署 AdminSite 时,该站点提供的视图可以使用Django的 URL反转系统 访问。

AdminSite 提供以下命名的URL模式:

网址名称

参数

指数

index

 

登录

login

 

登出

logout

 

密码更改

password_change

 

密码更改完成

password_change_done

 

i18n JavaScript

jsi18n

 

应用程序索引页

app_list

app_label

重定向到对象的页面

view_on_site

content_type_idobject_id

每个 ModelAdmin 实例提供一组额外的命名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:

网址名称

参数

密码更改

auth_user_password_change

user_id

这些命名的URL使用应用程序命名空间 admin 注册,并使用与站点实例名称对应的实例名称空间。

所以,如果你想得到一个特定的 Choice 对象(从poll应用程序)在默认管理员的更改视图的引用,你会调用:

>>> from django.urls import reverse
>>> c = Choice.objects.get(...)
>>> change_url = reverse('admin:polls_choice_change', args=(c.id,))

这将找到管理应用程序的第一个注册实例(无论实例名称),并解析到该实例中更改 poll.Choice 实例的视图。

如果要在特定管理实例中查找URL,请提供该实例的名称作为反向调用的 current_app 提示。例如,如果您特别需要来自名为 custom 的管理实例的管理视图,则需要调用:

>>> change_url = reverse('admin:polls_choice_change', args=(c.id,), current_app='custom')

有关更多详细信息,请参阅有关 颠倒命名空间URL 的文档。

为了允许更容易地反转模板中的管理URL,Django提供了一个 admin_urlname 过滤器,它接受一个动作作为参数:

{% load admin_urls %}
<a href="{% url opts|admin_urlname:'add' %}">Add user</a>
<a href="{% url opts|admin_urlname:'delete' user.pk %}">Delete this user</a>

上述示例中的操作与上述 ModelAdmin 实例的URL名称的最后一部分匹配。 opts 变量可以是具有 app_labelmodel_name 属性的任何对象,通常由当前模型的管理视图提供。

staff_member_required 装饰器

staff_member_required(redirect_field_name='next', login_url='admin:login')

此装饰器用于需要授权的管理视图。使用此函数装饰的视图将具有以下行为:

  • 如果用户已登录,是工作人员(User.is_staff=True),并且处于活动状态(User.is_active=True),则正常执行视图。

  • 否则,请求将被重定向到由 login_url 参数指定的URL,其中原始请求的路径在由 redirect_field_name 指定的查询字符串变量中。例如:/admin/login/?next=/admin/polls/question/3/

用法示例:

from django.contrib.admin.views.decorators import staff_member_required

@staff_member_required
def my_view(request):
    ...