Django管理后台站点

Django最强大的部分之一是自动生成的管理后台界面。 它从你的模型中读取元数据,以提供一个快速的、以模型为中心的界面,信任的用户可以在这里管理你网站上的内容。 建议管理后台仅作为组织的一个内部管理工具使用。 它不是为了建立你的整个前端。

管理站点有许多hook用于定制,但要注意试图专门使用这些hook。 如果你需要提供一个更加以流程为中心的界面,它抽象出数据库表和字段的实现细节,那么可能需要编写自己的视图。

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

概述

通过使用startproject创建的默认项目模版中,管理后台已启用。

下面的一些要求作为参考:

  1. 添加 'django.contrib.admin'INSTALLED_APPS 设置中.
  2. admin有四个依赖 — django.contrib.authdjango.contrib.contenttypesdjango.contrib.messagesdjango.contrib.sessions 如果这些应用没有在INSTALLED_APPS列表中, 那你要添加它们。
  3. 添加django.contrib.auth.context_processors.authdjango.contrib.messages.context_processors.messagesTEMPLATES中定义的DjangoTemplates后端的'context_processors'选项中,并添加django.contrib.auth.middleware.AuthenticationMiddlewaredjango.contrib.messages.middleware.MessageMiddlewareMIDDLEWARE中。 默认情况下它们都已经添加,除非你手动调整过设置,否则不需要自己添加。
  4. 确定你的应用中的哪些模型在管理后台界面中应该可以编辑。
  5. 给上面的每个模型创建一个ModelAdmin类,封装模型自定义的管理后台功能和选项。
  6. 实例化AdminSite并且告诉它你的每一个模型和ModelAdmin类。
  7. AdminSite实例hook到URLconf。

做完这些步骤之后,通过访问你hook进的URL(默认是/admin/),将能够使用你的Django管理后台站点。 如果你需要创建一个登录用户,可以使用createsuperuser命令。

其它主题

请参见

如何在产品中使用admin相关的静态文件(图片,JavaScript和CSS)的办法, 请参阅Serving files

还有什么问题? 试试 FAQ: The admin.

ModelAdmin对象

class ModelAdmin[source]

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)[source]

还可以用一个装饰器来注册您的ModelAdmin类(这里有关装饰器的详细信息,请参考python中的相关说明):

from django.contrib import admin
from .models import Author

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

如果你使用的不是默认的AdminSite,那么这个装饰器可以接收一些ModelAdmin作为参数,以及一个可选的关键字参数 site :(这里使用装饰器来注册需要注册的类和模块的,请特别留意紧跟装饰器后面关于ModelAdmin的声明,前面是Author,后面是PersonAdmin,我的理解是后一种情况 下注册的类都可以用PersonAdmin来作为接口):

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

在python2中,如果您在类的__init__())方法中引用了模型的admin类,则不能使用此装饰器,例如, super(PersonAdmin, self).__ init __(* args, ** kwargs) 但是,在Python3中,通过使用super().__ init __(* args, ** kwargs) t2 >可以避免这个问题; 在python2中,你必须使用admin.site.register()而不能使用装饰器方式。

探索admin文件

当你将 'django.contrib.admin'加入到INSTALLED_APPS 设置中, Django就会自动搜索每个应用的admin模块并将其导入。

class apps.AdminConfig

这是 admin的默认AppConfig 类. 它在 Django 启动时调用autodiscover() .

class apps.SimpleAdminConfig

这个类和 AdminConfig的作用一样,除了它不调用autodiscover().

autodiscover()[source]

这个函数尝试导入每个安装的应用中的admin 模块。 这些模块用于注册模型到Admin 中。

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

如果您正在使用自定义 AdminSite,则通常会将所有ModelAdmin子类导入到代码中,并将其注册到自定义AdminSite 在这种情况下, 为了禁用auto-discovery,在你的INSTALLED_APPS 设置中,应该用 'django.contrib.admin'代替'django.contrib.admin.apps.SimpleAdminConfig'

ModelAdmin的选项

ModelAdmin 非常灵活。 它有几个选项来处理自定义界面。 所有的选项都在 ModelAdmin 子类中定义:

from django.contrib import admin

class AuthorAdmin(admin.ModelAdmin):
    date_hierarchy = 'pub_date'
ModelAdmin.actions

在修改列表页面可用的操作列表。 详细信息请查看Admin actions .

ModelAdmin.actions_on_top
ModelAdmin.actions_on_bottom

控制actions的下拉框出现在页面的位置。 默认情况下,管理员更改列表显示页面顶部的操作(actions_on_top = True; actions_on_bottom t4 > = False)。

ModelAdmin.actions_selection_counter

控制选择计数器是否紧挨着下拉菜单action 默认的admin 更改列表将会显示它 (actions_selection_counter = True).

ModelAdmin.date_hierarchy

把 date_hierarchy 设置为在你的model 中的DateField或DateTimeField的字段名,然后更改列表页面将包含这个字段基于日期的下拉导航。

例如:

date_hierarchy = 'pub_date'

您也可以使用__查找在相关模型上指定一个字段,例如:

date_hierarchy = 'author__pub_date'

这将根据现有数据智能地填充自己,例如,如果所有的数据都是一个月里的, 它将只显示天级别的数据.

在Django更改1.11:

添加了相关模型引用字段的能力。

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

如果你希望title 模型的表单只包含nameAuthor 字段, 你应该显式说明fieldsexclude,像这样:

from django.contrib import admin

class AuthorAdmin(admin.ModelAdmin):
    fields = ('name', 'title')

class AuthorAdmin(admin.ModelAdmin):
    exclude = ('birth_date',)

由于Author 模型只有三个字段,birth_datetitlename,上述声明产生的表单将包含完全相同的字段。

ModelAdmin.fields

使用fields选项可以在“添加”和“更改”页面上的表单中进行简单的布局更改,例如仅显示可用字段的一个子集,修改其顺序或将其分组为行。 例如,可以定义一个简单的管理表单的版本使用django.contrib.flatpages.models.FlatPage 模块像下面这样:

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

在上面的例子中, 只有字段content, titleurl 将会在表单中顺序的显示. fields能够包含在 ModelAdmin.readonly_fields 中定义的作为只读显示的值

对于更复杂的布局需求,请参阅fieldsets选项。

不同于 list_displayfields 选项 只包含model中的字段名或者通过form指定的表单。 只有当它们列在readonly_fields中,它才能包含callables

要在同一行显示多个字段, 就把那些字段打包在一个元组里。 在此示例中,urltitle字段将显示在同一行上,content字段将在其自己的行下显示:

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

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

如果editable=Truefieldsets 选项都不存在, Django将会默认显示每一个不是 fields 并且 AutoField的字段, 在单一的字段集,和在模块中定义的字段有相同的顺序

ModelAdmin.fieldsets

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

fieldsets 是一个以二元元组为元素的列表, 每一个二元元组代表一个在管理表单的 <fieldset> ( <fieldset> 是表单的一部分.)

二元元组的格式是 (name, field_options), 其中 name 是一个字符串相当于 fieldset的标题, field_options 是一个关于 fieldset的字典信息,一个字段列表包含在里面。

一个完整的例子, 来自于django.contrib.flatpages.models.FlatPage 模块:

from django.contrib import admin

class FlatPageAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {
            'fields': ('url', 'title', 'content', 'sites')
        }),
        ('Advanced options', {
            'classes': ('collapse',),
            'fields': ('registration_required', 'template_name'),
        }),
    )

在管理界面的结果看起来像这样:

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

如果editable=Truefields 选项都不存在, Django将会默认显示每一个不是 fieldsets 并且 AutoField的字段, 在单一的字段集,和在模块中定义的字段有相同的顺序。

field_options 字典有以下关键字:

  • fields

    字段名元组将显示在该fieldset. 此键必选.

    例如:

    {
    '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'),
    }
    

    通过默认的管理站点样式表定义的两个有用的classes 是 collapsewide. Fieldsets 使用 collapse 样式将会在初始化时展开并且替换掉一个 “click to expand” 链接. Fieldsets 使用 wide 样式将会有额外的水平空格.

  • description

    一个可选择额外文本的字符串显示在每一个fieldset的顶部,在fieldset头部的底下. 字符串没有被TabularInline 渲染由于它的布局.

    记住这个值不是 HTML-escaped 当它显示在管理接口中时. 如果你愿意,这允许你包括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() 方法自定义默认的表单,而不用指定一个全新的表单。

例子见Adding custom validation to the admin部分。

如果你在ModelForm中定义 Meta.exclude属性,那么也必须定义 Meta.modelMeta.fields属性。 然而,当admin本身定义了fields,则Meta.fields属性将被忽略。

如果ModelAdmin 仅仅只是给Admin 使用,那么最简单的解决方法就是忽略Meta.model 属性,因为ModelForm 将自动选择应该使用的模型。 或者,你也可以设置在 Meta 类中的 fields = [] 来满足 ModelForm 的合法性。

如果 excludeModelAdmin 同时定义了一个 ModelForm 选项,那么 ModelAdmin 具有更高的优先级:

from django import forms
from django.contrib import admin
from myapp.models import Person

class PersonForm(forms.ModelForm):

    class Meta:
        model = Person
        exclude = ['name']

class PersonAdmin(admin.ModelAdmin):
    exclude = ['age']
    form = PersonForm

在上例中, “age” 字段将被排除而 “name” 字段将被包含在最终产生的表单中。

ModelAdmin.formfield_overrides

这个属性通过一种临时的方案来覆盖现有的模型中Field (字段)类型在admin site中的显示类型。 formfield_overrides 在类初始化的时候通过一个字典类型的变量来对应模型字段类型与实际重载类型的关系。

因为概念有点抽象,所以让我们来举一个具体的例子。 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},
    }

注意字典的键是一个实际的字段类型,而不是一个具体的字符。 该值是另一个字典;这些参数将被传递给表单域的__init__()方法。 有关详细信息,请参见The Forms API

警告

如果你想用一个关系字段的自定义界面 (即 ForeignKey 或者 ManyToManyField), 确保你没有在raw_id_fields or radio_fields中included那个字段名。

radio_fields不会让您更改raw_id_fieldsformfield_overrides设置的关系字段上的窗口小部件。 这是因为raw_id_fieldsradio_fields暗示自己的自定义小部件。

ModelAdmin.inlines

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

ModelAdmin.list_display

使用list_display 去控制哪些字段会显示在Admin 的修改列表页面中。

例如:

list_display = ('first_name', 'last_name')

如果你没有设置list_display(),Admin 站点将只显示一列表示每个对象的__str__() (Python 2 中是__unicode__)。

list_display中,你有4种赋值方式可以使用:

  • 模型的字段。 像这样:

    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,一个空字符串,或没有元素的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')
    
        def birth_date_view(self, obj):
             return obj.birth_date
    
        birth_date_view.empty_value_display = 'unknown'
    
  • 如果给出的字符串是模型、True 的一个方法或一个返回 True 或False 的可调用的方法,然后赋值给方法的boolean 属性一个ModelAdmin值, 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')
    
  • list_display(Python 2 上是__unicode__())方法在__str__() 中同样合法,就和任何其他模型方法一样,所以下面这样写完全OK︰

    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 在Admin 中按照按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() 只能使用 short_description 函数, 能使用@property 装饰器。

    像这样:

    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',)
    
  • <th> 中的字段名称还将作为HTML 输出的CSS 类, 形式为每个column-<field_name> 元素上具有list_display 例如这可以用于在CSS 文件中设置列的宽度。

  • Django 会尝试以下面的顺序解释list_display 的每个元素︰

    • 模型的字段。
    • 可调用对象。
    • 表示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 设置激活激活Admin 修改列表页面右侧栏中的过滤器,如下面的屏幕快照所示︰

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

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

  • 字段名称,其指定的字段应该是ManyToManyFieldIntegerFieldForeignKeyDateFieldCharFieldBooleanFieldDateTimeField,例如︰

    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 设置控制Admin 修改列表页面每页中显示多少项。 默认设置为100

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

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

当值为True时,将始终调用select_related() 当值设置为False时,如果存在任何ForeignKey,Django将查看list_display并调用select_related()

如果您需要更细粒度的控制,请使用元组(或列表)作为list_select_related的值。 空元组将阻止Django调用select_related 任何其他元组将直接传递到select_related作为参数。 像这样:

class ArticleAdmin(admin.ModelAdmin):
    list_select_related = ('author', 'category')

将会调用select_related('author', 'category').

如果需要根据请求指定动态值,则可以实现get_list_select_related()方法。

ModelAdmin.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 不能接受 DateTimeField, ForeignKey, OneToOneField, 和 ManyToManyField 字段.

ModelAdmin. preserve_filters T0> ¶ T1>

管理员现在在创建,编辑或删除对象后保留列表视图中的过滤器。 您可以将此属性设置为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模块中的VERTICALHORIZONTAL

除非是choices或设置了ForeignKey,否则不要在radio_fields中包含字段。

ModelAdmin.raw_id_fields

默认情况下,Django的管理员为ForeignKey的字段使用一个下拉菜单(<select>). 有时候你不想在下拉菜单中显示所有相关实例产生的开销。

raw_id_fields是一个字段列表,你希望将ForeignKeyManyToManyField 转换成Input 窗口部件:

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

如果该字段是一个ForeignKeyInput raw_id_fields Widget 应该包含一个外键,或者如果字段是一个ManyToManyField 则应该是一个逗号分隔的值的列表。 raw_id_fields Widget 在字段旁边显示一个放大镜按钮,允许用户搜索并选择一个值︰

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

默认情况下,管理后台将所有字段显示为可编辑。 此选项中的任何字段(应为listtuple)将按原样显示其数据,不可编辑;它们也被排除在用于创建和编辑的ModelForm之外。 请注意,指定ModelAdmin.fieldsModelAdmin.fieldsets时,只读字段必须包含进去才能显示(否则将被忽略)。

如果在未通过ModelAdmin.fieldsModelAdmin.fieldsets定义显式排序的情况下使用readonly_fields,则它们将在所有可编辑字段之后添加。

只读字段不仅可以显示模型字段中的数据,还可以显示模型方法的输出或ModelAdmin类本身的方法。 这与ModelAdmin.list_display的行为非常相似。 这提供了一种使用管理界面提供对正在编辑的对象的状态的反馈的简单方法,例如:

from django.contrib import admin
from django.utils.html import format_html_join
from django.utils.safestring import mark_safe

class PersonAdmin(admin.ModelAdmin):
    readonly_fields = ('address_report',)

    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的功能类似一个模型字段的verbose_name
    address_report.short_description = "Address"
ModelAdmin.save_as

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

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

默认情况下,save_as 设置为False

ModelAdmin.save_as_continue
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 设置启用Admin 更改列表页面上的搜索框。 此属性应设置为每当有人在该文本框中提交搜索查询将搜索的字段名称的列表。

这些字段应该是某种文本字段,如CharFieldTextField 你还可以通过查询API 的"跟随"符号进行ForeignKeyManyToManyField 上的关联查找:

search_fields = ['foreign_key__related_fieldname']

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

search_fields = ['user__email']

如果有人在Admin 搜索框中进行搜索,Django 拆分搜索查询为单词并返回包含每个单词的所有对象,不区分大小写,其中每个单词必须在至少一个search_fields 例如,如果search_fields 设置为['first_name', 'last_name'],用户搜索john lennon,Django 的行为将相当于下面的这个WHERE SQL 子句︰

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 的行为将等同于下面这个WHERE SQL 字句:

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 的行为将等同于下面这个WHERE SQL 字句:

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 结果 103 total))。 如果此选项设置为False,则像99 结果 (显示

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

ModelAdmin.view_on_site

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

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

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

from django.contrib import admin

class PersonAdmin(admin.ModelAdmin):
    view_on_site = False

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

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

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

自定义模板选项

Overriding admin templates 一节描述如何重写或扩展默认Admin 模板。 使用以下选项来重写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
Django中的新功能1.11。

response_add()response_change()response_delete()使用的自定义模板的路径。

ModelAdmin的方法

警告

当覆盖ModelAdmin.save_model()ModelAdmin.delete_model()时,代码必须保存/删除对象。 它们不是为了否决权,而是允许您执行额外的操作。

ModelAdmin.save_model(request, obj, form, change)[source]

The save_model method is given the HttpRequest, a model instance, a ModelForm instance, and a boolean value based on whether it is adding or changing the object. 覆盖此方法允许进行前或后保存操作。 使用Model.save()调用super().save_model()来保存对象。

例如,在保存之前将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)[source]

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

ModelAdmin.save_formset(request, form, formset, change)[source]

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

例如,要将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()

另请参见Saving objects in the 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)[source]

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') ,例如,这将导致数字字段的字符串比较 ... 要么 UPPER( “polls_choice”。 “票” ::文) = UPPER( '4') 在PostgreSQL上。

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

ModelAdmin.get_readonly_fields(request, obj=None)

list方法在添加表单上给予tupleobj(或HttpRequest),希望返回将以只读形式显示的字段名称的get_readonly_fieldsNone,如上面在ModelAdmin.readonly_fields部分中所述。

ModelAdmin.get_prepopulated_fields(request, obj=None)

dictionary方法在添加表单上给予objHttpRequest(或get_prepopulated_fields),预期返回None,如上面在ModelAdmin.prepopulated_fields部分中所述。

ModelAdmin.get_list_display(request)[source]

list方法被赋予HttpRequest,并且希望返回字段名称的get_list_displaytuple显示在如上所述的ModelAdmin.list_display部分中的changelist视图上。

The get_list_display_links method is given the HttpRequest and the list or tuple returned by ModelAdmin.get_list_display(). 预期将返回更改列表上将链接到更改视图的字段名称的tuplelistNone,如上所述在ModelAdmin.list_display_links部分中。

ModelAdmin.get_exclude(request, obj=None)
Django中的新功能1.11。

The get_exclude method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return a list of fields, as described in ModelAdmin.exclude.

ModelAdmin.get_fields(request, obj=None)[source]

obj方法被赋予HttpRequestget_fields被编辑(或在添加表单上None),希望返回字段列表,如上面在ModelAdmin.fields部分中所述。

ModelAdmin.get_fieldsets(request, obj=None)

<fieldset>方法是在添加表单上给予objHttpRequest(或get_fieldsets),期望返回二元组列表,其中每个二元组在管理表单页面上表示None,如上面在ModelAdmin.fieldsets部分。

ModelAdmin.get_list_filter(request)[source]

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

The get_list_select_related method is given the HttpRequest and should return a boolean or list as ModelAdmin.list_select_related does.

ModelAdmin.get_search_fields(request)[source]

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

ModelAdmin.get_inline_instances(request, obj=None)[source]

list方法在添加表单上给予tupleobj(或HttpRequest),预期会返回get_inline_instancesNoneInlineModelAdmin对象,如下面的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()[source]

get_urlsModelAdmin 方法返回ModelAdmin 将要用到的URLs,方式与URLconf 相同。 因此,你可以用URL dispatcher 中所述的方式扩展它们︰

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 的布局,可以从admin/base_site.html 扩展︰

{% extends "admin/base_site.html" %}
{% block content %}
...
{% endblock %}

请注意,自定义的模式包含在正常的Admin URLs之前:Admin URL 模式非常宽松,将匹配几乎任何内容,因此你通常要追加自定义的URLs 到内置的URLs 前面。

在此示例中,/admin/ 的访问点将是/admin/myapp/mymodel/my_view/(假设Admin URLs 包含在my_view 下)。

但是, 上述定义的函数self.my_view 将遇到两个问题:

  • 执行任何权限检查,所以会向一般公众开放。
  • 提供任何HTTP头的详细信息以防止缓存。 这意味着,如果页面从数据库检索数据,而且缓存中间件处于活动状态,页面可能显示过时的信息。

因为这通常不是你想要的,Django 提供一个方便的封装函数来检查权限并标记视图为不可缓存的。 这个包装器在ModelAdmin实例中是AdminSite.admin_view()(即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

请注意上述第5行中的被封装的视图︰

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

此包装将保护self.my_view未经授权的访问,并将应用django.views.decorators.cache.never_cache()装饰器,以确保缓存不缓存中间件是活动的。

如果该页面是可缓存的,但你仍然想要执行权限检查,你可以传递cacheable=TrueAdminSite.admin_view() 参数︰

url(r'^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)[source]

返回Admin中添加和更改视图使用的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)[source]

产量(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 没有:
                continue
            yield inline.get_formset(request, obj), inline
ModelAdmin.formfield_for_foreignkey(db_field, request, **kwargs)

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

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)

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

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_choice_fieldformfield_for_manytomany方法类似,可以覆盖formfield_for_foreignkey方法更改已声明选择的字段的默认窗体字段。 例如,如果超级用户可用的选择应与正式工作人员可用的选项不同,则可按以下步骤操作:

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)

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

ModelAdmin.get_changelist(request, **kwargs)[source]

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

ModelAdmin.get_changelist_form(request, **kwargs)[source]

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

from django import forms

class MyForm(forms.ModelForm):
    pass

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

如果你在ModelForm中定义 Meta.exclude属性,那么也必须定义 Meta.modelMeta.fields属性。 但是,ModelAdmin会忽略此值,并使用ModelAdmin.list_editable属性覆盖该值。 最简单的解决方案是省略Meta.model属性,因为ModelAdmin将提供要使用的正确模型。

ModelAdmin.get_changelist_formset(request, **kwargs)[source]

如果使用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.lookup_allowed(lookup, value)

可以从URL查询字符串中的查找过滤更改列表页面中的对象。 例如,这是list_filter的工作原理。 查询与QuerySet.filter()(例如user__email=user@example.com)中使用的查找类似。 由于查询字符串中的查询可以由用户操纵,因此必须对其进行清理,以防止未经授权的数据暴露。

给定了lookup_allowed()方法,从查询字符串(例如'user__email')和相应的值(例如'user@example.com'),并返回一个布尔值,表示是否允许使用参数过滤changelist的QuerySet 如果lookup_allowed()返回False,则会引发DisallowedModelAdminLookupSuspiciousOperation的子类)。

默认情况下,lookup_allowed()允许访问模型的本地字段,list_filter中使用的字段路径(但不是来自get_list_filter()的路径)并且limit_choices_to所需的查找在raw_id_fields中正常运行。

覆盖此方法可自定义ModelAdmin子类允许的查找。

ModelAdmin.has_add_permission(request)

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

ModelAdmin.has_change_permission(request, obj=None)

如果允许编辑obj,则应返回True,否则返回False 如果obj为False,则应返回TrueNone以指示是否允许对此类对象进行编辑(例如,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)[source]

使用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)[source]

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

ModelAdmin.response_add(request, obj, post_url_continue=None)[source]

add_view()阶段确定HttpResponse

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

ModelAdmin.response_change(request, obj)[source]

确定change_view() 阶段的HttpResponse

response_change 在Admin 表单提交并保存该对象和所有相关的实例之后调用。 您可以重写它来更改对象修改之后的默认行为。

ModelAdmin.response_delete(request, obj_display, obj_id)[source]

delete_view()阶段确定HttpResponse

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

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

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

ModelAdmin.get_changeform_initial_data(request)[source]

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

该方法应该返回表单中的字典 { '字段名': 'fieldval'}:

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

其他方法

ModelAdmin.add_view(request, form_url='', extra_context=None)[source]

Django视图为模型实例添加页面。 见下面的注释。

ModelAdmin.change_view(request, object_id, form_url='', extra_context=None)[source]

模型实例编辑页面的Django视图。 见下面的注释。

ModelAdmin.changelist_view(request, extra_context=None)[source]

Django视图为模型实例更改列表/操作页面。 见下面的注释。

ModelAdmin.delete_view(request, object_id, extra_context=None)[source]

模型实例删除确认页面的Django 视图。 见下面的注释。

ModelAdmin.history_view(request, object_id, extra_context=None)[source]

显示给定模型实例的修改历史的页面的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 documentation

ModelAdmin资产定义

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

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

staticfiles appSTATIC_URL(或MEDIA_URL如果STATIC_URLNone资产路径。 相同的规则适用于表单上的regular asset definitions on forms

jQuery

Django管理JavaScript使用jQuery库。

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

在Django更改1.10:

嵌入式jQuery从2.1.4升级到2.2.3。

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

Django提供了jQuery的未压缩和“缩小”版本,分别是jquery.jsjquery.min.js

ModelAdminInlineModelAdmin具有media属性,可返回存储到JavaScript文件的路径的Media对象列表形式和/或格式。 如果DEBUGTrue,它将返回各种JavaScript文件的未压缩版本,包括jquery.js;如果没有,它将返回“最小化”版本。

向admin 添加自定义验证

在管理员中添加数据的自定义验证是很容易的。 自动管理界面重用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否则会破坏。 有关详细信息,请参阅custom validation上的forms文档,更具体地说,model form validation notes

InlineModelAdmin对象

class InlineModelAdmin
class TabularInline[source]
class StackedInline[source]

此管理界面能够在一个界面编辑多个Model。 这些称为内联。 假设你有这两个模型:

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)

The first step in displaying this intermediate model in the admin is to define an inline class for the Membership model: 您可以通过在ModelAdmin.inlines中指定模型来为模型添加内联:

from django.contrib import admin

class BookInline(admin.TabularInline):
    model = Book

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

Django提供了两个InlineModelAdmin的子类如下:

这两者之间仅仅是在用于呈现他们的模板上有区别。

InlineModelAdmin options

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

InlineModelAdmin类添加:

InlineModelAdmin.model

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

InlineModelAdmin.fk_name

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

InlineModelAdmin.formset

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

InlineModelAdmin.form

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

警告

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

InlineModelAdmin.classes
Django中的新功能1.10。

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

InlineModelAdmin.extra

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

对于具有启用JavaScript的浏览器的用户,提供了“添加另一个”链接,以允许除了由于extra参数提供的内容之外添加任意数量的其他内联。

如果当前显示的表单数量超过max_num,或者用户未启用JavaScript,则不会显示动态链接。

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

InlineModelAdmin.max_num

这控制在内联中显示的表单的最大数量。 这不直接与对象的数量相关,但如果值足够小,可以。 有关详细信息,请参阅Limiting the number of editable objects

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

InlineModelAdmin。 MIN_NUM T0> ¶ T1>

这控制在内联中显示的表单的最小数量。 有关详细信息,请参阅modelformset_factory()

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

InlineModelAdmin。 raw_id_fields T0> ¶ T1>

By default, Django’s admin uses a select-box interface (<select>) for fields that are ForeignKey. 有时候你不想在下拉菜单中显示所有相关实例产生的开销。

ForeignKey 是一个字段列表,你希望将Inputraw_id_fields 转换成ManyToManyField Widget:

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

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

InlineModelAdmin。 verbose_name T0> ¶ T1>

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

InlineModelAdmin。 verbose_name_plural T0> ¶ T1>

覆盖模型的内部verbose_name_plural类中的Meta

InlineModelAdmin。 can_delete T0> ¶ T1>

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

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

InlineModelAdmin。get_formset请求obj =无** kwargs

返回BaseInlineFormSet类,以在管理员添加/更改视图中使用。 请参阅ModelAdmin.get_formsets_with_inlines的示例。

InlineModelAdmin。get_extra请求obj =无** 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请求obj =无** 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请求obj =无** 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定义,模型中的每个多对多字段将由标准HTML &lt; select multiple> t4>,水平或垂直过滤器或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.through through属性是对管理多对多关系的模型的引用。 在定义多对多字段时,此模型由Django自动创建。

其次,GroupAdmin必须手动排除members字段。 Django在定义关系(在这种情况下,Group)的模型上显示多对多字段的管理窗口小部件。 如果要使用内联模型来表示多对多关系,则必须告知Django的管理员而不是显示此窗口小部件 - 否则您最终会在管理页面上看到两个窗口小部件,用于管理关系。

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

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

使用多对多中介模型

当您使用ManyToManyFieldthrough参数指定中介模型时,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, 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)

在admin中显示此中间模型的第一步是为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)

现在,您的管理网站已设置为从GroupPerson详细信息页面内联编辑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)

If you want to allow editing and creating an Image instance on the Product, add/change views you can use GenericTabularInline or GenericStackedInline (both subclasses of GenericInlineModelAdmin) provided by admin. 它们分别为表示内联对象的表单分别执行表格和堆叠的视觉布局,就像它们的非通用对象一样。 他们的行为就像任何其他内联一样。 在此示例应用的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 documentation

覆盖管理模板

相对重写一个admin站点的各类页面,直接在admin站点默认templates上直接进行修改是件相对简单的事。 你甚至可以为特定的应用或一个特定的模型覆盖少量的这些模板。

设置你的项目管理模板目录

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

如要覆盖一个或多个模板,首先在你的项目的admin 目录中创建一个templates 目录。 它可以是你在TEMPLATES 设置的DjangoTemplates 后端的DIRS 选项中指定的任何目录。 If you have customized the 'loaders' option, be sure 'django.template.loaders.filesystem.Loader' appears before 'django.template.loaders.app_directories.Loader' so that your custom templates will be found by the template loading system before those that are included with django.contrib.admin.

admin 目录下, 以你的应用名创建子目录. 在应用名的目录下,以你模型层的名字创建子目录. 注意:admin应用会以小写名的形式在目录下查找模型, 如果你想在大小写敏感的文件系统上运行app,请确保以小写形式命名目录.

为一个特定的app重写admin模板, 需要拷贝django/contrib/admin/templates/admin 目录到你刚才创建的目录下, 并且修改它们.

For example, if we wanted to add a tool to the change list view for all the models in an app named templates/admin/my_app/, we would copy contrib/admin/templates/admin/change_list.html to the my_app directory of our project, and make any necessary changes.

如果我们只想为名为“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">{% 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中所有模型的更改表单上。

Templates which may be overridden per app or model

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

  • app_index.html
  • change_form.html
  • change_list.html
  • delete_confirmation.html
  • object_history.html
  • popup_response.html
在Django更改1.11:

覆盖popup_response.html模板的功能已添加。

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

一些Admin的模板,例如change_list_results.html 用于呈现自定义包含标签。 这些可能会被覆盖,但在这种情况下你可能最好是创建您自己的版本Tag,并给它一个不同的名称。 这样你可以有选择地使用它。

根和登录模板

如果你想要更改主页、 登录或登出页面的模板,你最后创建你自己的AdminSite 实例(见下文),并更改AdminSite.index_templateAdminSite.login_templateAdminSite.logout_template 属性。

AdminSite对象

class AdminSite(name='admin')[source]

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

当构造AdminSite 的实例时,你可以使用name 参数给构造函数提供一个唯一的实例名称。 这个实例名称用于标识实例,尤其是reversing admin URLs 的时候。 如果没有提供实例的名称,将使用默认的实例名称admin 有关自定义AdminSite 类的示例,请参见Customizing the AdminSite class

AdminSite属性

Overriding admin templates中所述,模板可以覆盖或扩展基础的Admin 模板。

AdminSite.site_header

每个Admin 页面顶部的文本,形式为<h1>(字符串)。 默认为 “Django administration”。

AdminSite.site_title

每个Admin 页面底部的文本,形式为<title>(字符串)。 默认为“Django site admin”。

AdminSite.site_url

每个Admin 页面顶部"View site" 链接的URL。 默认情况下,site_url/ 设置为None 可以删除这个链接。

对于在子路径上运行的站点,each_context()方法会检查当前请求是否具有request.META['SCRIPT_NAME']设置并使用该值,如果site_url未设置为/以外的其他内容。

在Django更改1.10:

上一段描述的SCRIPT_NAME支持已添加。

AdminSite.index_title

Admin 主页顶部的文本(一个字符串)。 默认为 “Site administration”。

AdminSite.index_template

Admin 站点主页的视图使用的自定义模板的路径。

AdminSite.app_index_template

Admin 站点app index 的视图使用的自定义模板的路径。

AdminSite.empty_value_display

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

AdminSite.login_template

Admin 站点登录视图使用的自定义模板的路径。

AdminSite.login_form

Admin 站点登录视图使用的AuthenticationForm 的子类。

AdminSite.logout_template

Admin 站点登出视图使用的自定义模板的路径。

AdminSite.password_change_template

Admin 站点密码修改视图使用的自定义模板的路径。

AdminSite.password_change_done_template

Admin 站点密码修改完成视图使用的自定义模板的路径。

AdminSite方法

AdminSite.each_context(request)[source]

返回一个字典,包含将放置在Admin 站点每个页面的模板上下文中的变量。

包含以下变量和默认值:

  • site_headerAdminSite.site_header

  • site_titleAdminSite.site_title

  • site_urlAdminSite.site_url

  • has_permissionAdminSite.has_permission()

  • available_apps:从当前用户可用的application registry中的应用程序列表。 列表中的每个条目都是表示具有以下密钥的应用程序的dict:

    • app_label:应用程序标签
    • app_url:管理员中的应用程序索引的URL
    • has_module_perms:一个布尔值,表示当前用户是否允许显示和访问模块的索引页面
    • models:应用程序中可用的模型列表

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

    • object_name:模型的类名
    • name:复数名称的模型
    • perms:a dict tracking addchangedelete permissions
    • admin_url:admin changelist模型的URL
    • add_url:添加新模型实例的admin URL
AdminSite.has_permission(request)[source]

对于给定的True,如果用户有权查看Admin 网站中的至少一个页面,则返回 HttpRequest 默认要求User.is_activeUser.is_staff 都为True

AdminSite.register(model_or_iterable, admin_class=None, **options)[source]

使用给定的admin_class注册给定的模型类(或模型类组成的可迭代对象)。 admin_class默认为ModelAdmin(默认的管理后台选项)。 如果给出了关键字参数 — 例如list_display — 它们将作为选项应用于admin_class。

如果模型是抽象的,则引发ImproperlyConfigured 如果模型已经注册则引发django.contrib.admin.sites.AlreadyRegistered

AdminSite的实例挂接到URLconf中

设置Django管理后台的最后一步是放置你的AdminSite到你的URLconf中。 将一个给定的URL指向AdminSite.urls方法就可以做到。 没有必要使用include()

在下面的示例中,我们注册默认的AdminSite实例django.contrib.admin.site到URL /admin/

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

urlpatterns = [
    url(r'^admin/', admin.site.urls),
]

定制AdminSite

如果你想要建立你自己的具有自定义行为Admin 站点,你可以自由地子类化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),
]

注意,当使用你自己的admin 实例时,你可能不希望自动发现AdminSite 模块,因为这将导入admin 模块到你的每个myproject.admin 模块中 。 这时,你需要将'django.contrib.admin' 而不是'django.contrib.admin.apps.SimpleAdminConfig' 放置在你的INSTALLED_APPS 设置中。

相同的URLconf 中的多个管理站点

在同一个Django供电的网站上创建管理站点的多个实例很容易。 只需要创建AdminSite 的多个实例并将每个实例放置在不同的URL 下。

在下面的示例中,AdminSite/advanced-admin/ 分别使用/basic-admin/myproject.admin.basic_site 实例和myproject.admin.advanced_site 实例表示不同版本的Admin 站点:

# 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 It should be set to either self.name if your view is on an AdminSite or self.admin_site.name if your view is on a ModelAdmin.

添加密码重置功能

您可以通过在URLconf中添加几行来将密码重置功能添加到管理站点。 具体操作就是加入下面四个正则规则。

from django.contrib.auth import views as auth_views

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

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

如果存在admin_password_reset命名的URL,则会在密码框下的默认管理登录页面上显示“忘记了您的密码?”链接。

LogEntry对象

楷模。 LogEntry T0> ¶ T1>

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()方法检索该值,而不是直接访问该值。

在Django更改1.10:

以前,此属性始终是一个简单的字符串。 它现在是JSON结构,以便可以使用当前用户语言翻译该消息。 老消息不变。

LogEntry方法

LogEntry.get_edited_object()

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

LogEntry.get_change_message()
Django中的新功能1.10。

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

反向解析管理后台的URL

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 用户名

这些命名URL 注册的应用命名空间为admin,实例命名空间为对应的AdminSite 实例的名称。

所以,如果你想要获取默认Admin 中,(polls 应用的) 一个特定的Choice 对象的更改视图的引用,你可以调用︰

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

这将查找Admin 应用中第一个注册的实例(无论实例名称是什么),并解析到poll.Choice 实例的更改视图。

如果你想要查找一个特定的Admin 实例中URL,请提供实例的名称作为current_app 给反向解析的调用 。 例如,如果你希望得到名为custom 的Admin 实例中的视图,你将需要调用︰

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

有关更多详细信息,请参阅reversing namespaced URLs 的文档。

为了让模板中反向解析Admin URL 更加容易,Django 提供一个admin_urlname 过滤器,它以Action 作为参数︰

{% 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>

在上面的例子中Action 将匹配上文所述的ModelAdmin 实例的URL 名称的最后部分。 model_name 变量可以是任何具有app_labelopts 属性的对象,通常由Admin 视图为当前的模型提供。

staff_member_required装饰器

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

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

  • 如果用户登录,是工作人员(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):
    ...