Django 1.8.2 文档

Django Admin 站点

Django 最强大的部分之一是自动生成的Admin 界面。它读取模型中的元数据来提供一个强大的、生产环境就绪的界面,使内容提供者能立即用它向站点中添加内容。在本文中,我们将讨论如何激活,使用和定制Django的管理界面。

概述

通过使用startproject 创建的默认项目模版中,Admin 已启用。

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

  1. 添加 'django.contrib.admin'INSTALLED_APPS 设置中.
  2. admin有四个依赖 - django.contrib.auth, django.contrib.contenttypes, django.contrib.messagesdjango.contrib.sessions. 如果这些应用没有在 INSTALLED_APPS 列表中, 那你要把它们添加到该列表中.
  3. django.contrib.messages.context_processors.messages 添加到TEMPLATESDjangoTemplates后台的'context_processors'选项中,同样把django.contrib.auth.middleware.AuthenticationMiddlewaredjango.contrib.messages.middleware.MessageMiddleware 添加到 MIDDLEWARE_CLASSES. (这些默认都是激活的,所以如果你手工操作过的话就需要按照以上方法进行设置..)
  4. 确定应用中的哪些模型应该在Admin 界面中可以编辑。
  5. 给每个模型创建一个ModelAdmin 类,封装模型自定义的Admin 功能和选项。
  6. 实例化AdminSite 并且告诉它你的每一个模块和ModelAdmin 类.
  7. AdminSite 实例绑定到URLconf。

做了这些步骤之后, 你将能够通过你已经绑定的URL来访问Django管理站点(默认是/admin/).

其他话题

注意

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

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

ModelAdmin objects

class ModelAdmin

ModelAdmin 类是模型在Admin 界面中的表示形式。通常,将它们在你的应用中的名为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并没有定义任何自定义的值。因此, 系统将使用默认的Admin 界面。如果对于默认的Admin 界面足够满意,那你根本不需要自己定义ModelAdmin 对象, 你可以直接注册模型类而无需提供ModelAdmin 的描述。那么上面的例子可以简化成:

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

admin.site.register(Author)

注册装饰器

register(*models[, site=django.admin.sites.site])
New in Django 1.7.

还可以用一个装饰来注册您的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

发现admin 文件

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

class apps.AdminConfig
New in Django 1.7.

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

class apps.SimpleAdminConfig
New in Django 1.7.

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

autodiscover()[source]

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

Changed in Django 1.7:

以前的Django版本推荐直接在URLconf中调用这个函数. Django 1.7不再需要这样. AdminConfig 能够自动的运行 auto-discovery.

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

Changed in Django 1.7:

在以前的版本中,admin需要被指示寻找 admin.py 文件通过 autodiscover(). 在Django 1.7, auto-discovery默认可用的,必须明确的使它失效当不需要时.

ModelAdmin options

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 bar 出现在页面的位置。默认情况下,admin的更改列表将操作显示在页面的顶部(actions_on_top = True;actions_on_bottom = False).

ModelAdmin.actions_selection_counter

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

ModelAdmin.date_hierarchy

date_hierarchy 设置为在你的model 中的DateFieldDateTimeField的字段名,然后更改列表将包含一个依据这个字段基于日期的下拉导航。

例如:

date_hierarchy = 'pub_date'

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

注意

date_hierarchy 在内部使用QuerySet.datetimes(). 当时区支持启用时,请参考它的一些文档说明。(USE_TZ = True).

ModelAdmin.exclude

如果设置了这个属性,它表示应该从表单中去掉的字段列表。

例如,让我们来考虑下面的模型:

from django.db import models

class Author(models.Model):
    name = models.CharField(max_length=100)
    title = models.CharField(max_length=3)
    birth_date = models.DateField(blank=True, null=True)

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

from django.contrib import admin

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

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

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

ModelAdmin.fields

如果需要实现字段的布局中的“添加” 和 “更改”,“更改”网页形式的简单改变像只显示可用字段的一个子集,你可以使用 fields选项修改他们的顺序或者行内分组(需要复杂布局的请参阅fieldsets 选项将在下一段讲到). 例如,可以定义一个简单的管理表单的版本使用django.contrib.flatpages.models.FlatPage 模块像下面这样:

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

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

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

要在同一行显示多个字段, 就把那些字段打包在一个元组里。例子中, urltitle 字段 会显示在同一行, content 字段将会显示在他们的下一行里:

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

注意

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

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

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': ('enable_comments', 'registration_required', 'template_name')
        }),
    )

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

../../../_images/flatfiles_admin.png

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

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 应用到 fieldset.

    例如:

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

Same as filter_horizontal, but uses a vertical display of the filter interface with the box of unselected options appearing above the box of selected options.

ModelAdmin.form

默认情况下, 会根据你的模型动态创建一个ModelForm它被用来创建呈现在添加/更改页面上的表单。你可以很容易的提供自己的ModelForm 来重写表单默认的添加/修改行为。或者,你可以使用ModelAdmin.get_form() 方法自定义默认的表单,而不用指定一个全新的表单。

例子见添加自定义验证到Admin 中部分。

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

如果ModelForm 仅仅只是给Admin 使用,那么最简单的解决方法就是忽略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

在上例中, “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__()(初始化方法) 中。See The Forms API for details.

警告

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

formfield_overrides won’t let you change the widget on relation fields that have raw_id_fields or radio_fields set. That’s because raw_id_fields and radio_fields imply custom widgets of their own.

ModelAdmin.inlines

See InlineModelAdmin objects below as well as 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_displaylist_display 的更多自定义方法请参见下文)。

  • 如果该字段为BooleanFieldNullBooleanField,Django 会显示漂亮的"on"或"off"图标而不是TrueFalse

  • 如果给出的字符串是模型、ModelAdmin 的一个方法或可调用对象,Django 将默认转义HTML输出。如果你不希望转义方法的输出,可以给方法一个allow_tags 属性,其值为True然而,为了避免XSS 漏洞,应该使用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)
    
        colored_name.allow_tags = True
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'last_name', 'colored_name')
    
  • 如果给出的字符串是模型、ModelAdmin 的一个方法或一个返回 True 或False 的可调用的方法,然后赋值给方法的boolean 属性一个True值, 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 中同样合法,就和任何其他模型方法一样,所以下面这样写完全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.allow_tags = True
        colored_first_name.admin_order_field = 'first_name'
    
    class PersonAdmin(admin.ModelAdmin):
        list_display = ('first_name', 'colored_first_name')
    

    上面的示例告诉Django 在Admin 中按照按colored_first_name 排序时依据first_name 字段。

    New in Django 1.7.

    要表示按照admin_order_field 降序排序,你可以在该字段名称前面使用一个连字符前缀。使用上面的示例,这会看起来像︰

    colored_first_name.admin_order_field = '-first_name'
    
  • list_display 的元素也可以是属性。不过请注意,由于方式属性在Python 中的工作方式,在属性上设置short_description 只能使用 property() 函数, 能使用@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',)
    
  • list_display 中的字段名称还将作为HTML 输出的CSS 类, 形式为每个<th> 元素上具有column-<field_name>例如这可以用于在CSS 文件中设置列的宽度。

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

    • 模型的字段。
    • 可调用对象。
    • 表示ModelAdmin 属性的字符串。
    • 表示模型属性的字符串。

    例如,如果first_name 既是模型的一个字段又是ModelAdmin 的一个属性,使用的将是模型字段。

Use list_display_links to control if and which fields in list_display should be linked to the “change” page for an object.

By default, the change list page will link the first column – the first field specified in list_display – to the change page for each item. But list_display_links lets you change this:

  • Set it to None to get no links at all.

  • Set it to a list or tuple of fields (in the same format as list_display) whose columns you want converted to links.

    You can specify one or many fields. As long as the fields appear in list_display, Django doesn’t care how many (or how few) fields are linked. The only requirement is that if you want to use list_display_links in this fashion, you must define list_display.

In this example, the first_name and last_name fields will be linked on the change list page:

class PersonAdmin(admin.ModelAdmin):
    list_display = ('first_name', 'last_name', 'birthday')
    list_display_links = ('first_name', 'last_name')

In this example, the change list page grid will have no links:

class AuditEntryAdmin(admin.ModelAdmin):
    list_display = ('timestamp', 'message')
    list_display_links = None
Changed in Django 1.7:

None was added as a valid list_display_links value.

ModelAdmin.list_editable

Set list_editable to a list of field names on the model which will allow editing on the change list page. That is, fields listed in list_editable will be displayed as form widgets on the change list page, allowing users to edit and save multiple rows at once.

Note

list_editable interacts with a couple of other options in particular ways; you should note the following rules:

  • Any field in list_editable must also be in list_display. You can’t edit a field that’s not displayed!
  • The same field can’t be listed in both list_editable and list_display_links – a field can’t be both a form and a link.

You’ll get a validation error if either of these rules are broken.

ModelAdmin.list_filter

list_filter 设置激活激活Admin 修改列表页面右侧栏中的过滤器,如下面的屏幕快照所示︰

../../../_images/users_changelist.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),
        )
    
    New in Django 1.8.

    你可以使用RelatedOnlyFieldListFilter 限制与该对象关联的模型的选项:

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

    假设authorUser 模型的一个ForeignKey,这将限制list_filter 的选项为编写过书籍的用户,而不是所有用户。

    注意

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

也可以指定自定义模板用于渲染列表筛选器︰

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

具体的例子请参见Django 提供的默认模板(admin/filter.html)。

ModelAdmin.list_max_show_all

Set list_max_show_all to control how many items can appear on a “Show all” admin change list page. The admin will display a “Show all” link on the change list only if the total result count is less than or equal to this setting. By default, this is set to 200.

ModelAdmin.list_per_page

list_per_page 设置控制Admin 修改列表页面每页中显示多少项。默认设置为100

Set list_select_related to tell Django to use select_related() in retrieving the list of objects on the admin change list page. This can save you a bunch of database queries.

The value should be either a boolean, a list or a tuple. Default is False.

When value is True, select_related() will always be called. 当值为False时,如果存在任何ForeignKey,Django将查看list_display并调用select_related()

If you need more fine-grained control, use a tuple (or list) as value for list_select_related. Empty tuple will prevent Django from calling select_related at all. Any other tuple will be passed directly to select_related as parameters. For example:

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

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

ModelAdmin.ordering

Set ordering to specify how lists of objects should be ordered in the Django admin views. This should be a list or tuple in the same format as a model’s ordering parameter.

If this isn’t provided, the Django admin will use the model’s default ordering.

If you need to specify a dynamic order (for example depending on user or language) you can implement a get_ordering() method.

ModelAdmin.paginator

The paginator class to be used for pagination. By default, django.core.paginator.Paginator is used. If the custom paginator class doesn’t have the same constructor interface as django.core.paginator.Paginator, you will also need to provide an implementation for ModelAdmin.get_paginator().

ModelAdmin.prepopulated_fields

prepopulated_fields设置为将字段名称映射到其应预先填充的字段的字典:

class ArticleAdmin(admin.ModelAdmin):
    prepopulated_fields = {"slug": ("title",)}

When set, the given fields will use a bit of JavaScript to populate from the fields assigned. The main use for this functionality is to automatically generate the value for SlugField fields from one or more other fields. The generated value is produced by concatenating the values of the source fields, and then by transforming that result into a valid slug (e.g. substituting dashes for spaces).

prepopulated_fields doesn’t accept DateTimeField, ForeignKey, nor ManyToManyField fields.

ModelAdmin.preserve_filters

The admin now preserves filters on the list view after creating, editing or deleting an object. You can restore the previous behavior of clearing filters by setting this attribute to False.

ModelAdmin.radio_fields

By default, Django’s admin uses a select-box interface (<select>) for fields that are ForeignKey or have choices set. If a field is present in radio_fields, Django will use a radio-button interface instead. Assuming group is a ForeignKey on the Person model:

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

You have the choice of using HORIZONTAL or VERTICAL from the django.contrib.admin module.

Don’t include a field in radio_fields unless it’s a ForeignKey or has choices set.

ModelAdmin.raw_id_fields

默认情况下,Django 的Admin 对ForeignKey 字段使用选择框表示 (<select>) 。有时候你不想在下拉菜单中显示所有相关实例产生的开销。

raw_id_fields 是一个字段列表,你希望将ForeignKeyManyToManyField 转换成Input Widget:

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

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

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

By default the admin shows all fields as editable. Any fields in this option (which should be a list or tuple) will display its data as-is and non-editable; they are also excluded from the ModelForm used for creating and editing. Note that when specifying ModelAdmin.fields or ModelAdmin.fieldsets the read-only fields must be present to be shown (they are ignored otherwise).

If readonly_fields is used without defining explicit ordering through ModelAdmin.fields or ModelAdmin.fieldsets they will be added last after all editable fields.

A read-only field can not only display data from a model’s field, it can also display the output of a model’s method or a method of the ModelAdmin class itself. This is very similar to the way ModelAdmin.list_display behaves. This provides an easy way to use the admin interface to provide feedback on the status of the objects being edited, for example:

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 "<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"
    # in this example, we have used HTML tags in the output
    address_report.allow_tags = True
ModelAdmin.save_as

save_as 设置启用Admin 更改表单上的“save as”功能。

通常情况下,对象有三个保存选项:"保存"、"保存并继续编辑"和"保存并添加另一个"。如果save_asTrue,"保存并添加另一个"将由"另存为"按钮取代。

"另存为"表示对象将被保存为一个新的对象 (带有一个新的 ID),而不是旧的对象。

默认情况下,save_as 设置为False

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'(包含空格)的所有记录。

@
Performs a full-text match. This is like the default search method but uses an index. Currently this is only available for MySQL.

如果你需要自定义搜索,你可以使用ModelAdmin.get_search_results() 来提供附件的或另外一种搜索行为。

ModelAdmin.show_full_result_count
New in Django 1.8.

Set show_full_result_count to control whether the full count of objects should be displayed on a filtered admin page (e.g. 99 results (103 total)). If this option is set to False, a text like 99 results (Show all) is displayed instead.

The default of show_full_result_count=True generates a query to perform a full count on the table which can be expensive if the table contains a large number of rows.

ModelAdmin.view_on_site
New in Django 1.7.

Set view_on_site to control whether or not to display the “View on site” link. This link should bring you to a URL where you can display the saved object.

This value can be either a boolean flag or a callable. If True (the default), the object’s get_absolute_url() method will be used to generate the url.

If your model has a get_absolute_url() method but you don’t want the “View on site” button to appear, you only need to set view_on_site to False:

from django.contrib import admin

class PersonAdmin(admin.ModelAdmin):
    view_on_site = False

In case it is a callable, it accepts the model instance as a parameter. For example:

from django.contrib import admin
from django.core.urlresolvers import reverse

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

自定义模板的选项

重写Admin模板 一节描述如何重写或扩展默认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() 使用的自定义模板,用于删除一个或多个对象时显示一个确认页。参见Action 的文档

ModelAdmin.object_history_template

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

ModelAdmin methods

Warning

ModelAdmin.save_model()ModelAdmin.delete_model()必须保存/删除对象,它们不是用于veto(否决)目的,而是允许您执行额外的操作。

ModelAdmin.save_model(request, obj, form, change)

save_model方法被赋予HttpRequest、模型实例、ModelForm实例和布尔值,基于它是adding(添加)还是changing(更改)对象。在这里您可以执行任何预保存或后保存操作。

例如,在保存之前将request.user附加到对象:

from django.contrib import admin

class ArticleAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        obj.save()
ModelAdmin.delete_model(request, obj)

delete_model方法给出了HttpRequest和模型实例。使用此方法执行预删除或后删除操作。

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

See also Saving objects in the formset.

ModelAdmin.get_ordering(request)

The get_ordering method takes a``request`` as parameter and is expected to return a list or tuple for ordering similar to the ordering attribute. For example:

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)

The get_search_results method modifies the list of objects displayed in to those that match the provided search term. It accepts the request, a queryset that applies the current filters, and the user-provided search term. It returns a tuple containing a queryset modified to implement the search, and a boolean indicating if the results may contain duplicates.

The default implementation searches the fields named in ModelAdmin.search_fields.

This method may be overridden with your own custom search method. For example, you might wish to search by an integer field, or use an external tool such as Solr or Haystack. You must establish if the queryset changes implemented by your search method may introduce duplicates into the results, and return True in the second element of the return value.

For example, to enable search by integer field, you could use:

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

The save_related method is given the HttpRequest, the parent ModelForm instance, the list of inline formsets and a boolean value based on whether the parent is being added or changed. Here you can do any pre- or post-save operations for objects related to the parent. Note that at this point the parent object and its form have already been saved.

ModelAdmin.get_readonly_fields(request, obj=None)

The get_readonly_fields method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return a list or tuple of field names that will be displayed as read-only, as described above in the ModelAdmin.readonly_fields section.

ModelAdmin.get_prepopulated_fields(request, obj=None)

The get_prepopulated_fields method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return a dictionary, as described above in the ModelAdmin.prepopulated_fields section.

ModelAdmin.get_list_display(request)

The get_list_display method is given the HttpRequest and is expected to return a list or tuple of field names that will be displayed on the changelist view as described above in the ModelAdmin.list_display section.

The get_list_display_links method is given the HttpRequest and the list or tuple returned by ModelAdmin.get_list_display(). It is expected to return either None or a list or tuple of field names on the changelist that will be linked to the change view, as described in the ModelAdmin.list_display_links section.

Changed in Django 1.7:

None was added as a valid get_list_display_links() return value.

ModelAdmin.get_fields(request, obj=None)
New in Django 1.7.

The get_fields 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 above in the ModelAdmin.fields section.

ModelAdmin.get_fieldsets(request, obj=None)

The get_fieldsets method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return a list of two-tuples, in which each two-tuple represents a <fieldset> on the admin form page, as described above in the ModelAdmin.fieldsets section.

ModelAdmin.get_list_filter(request)

The get_list_filter method is given the HttpRequest and is expected to return the same kind of sequence type as for the list_filter attribute.

ModelAdmin.get_search_fields(request)
New in Django 1.7.

The get_search_fields method is given the HttpRequest and is expected to return the same kind of sequence type as for the search_fields attribute.

ModelAdmin.get_inline_instances(request, obj=None)

The get_inline_instances method is given the HttpRequest and the obj being edited (or None on an add form) and is expected to return a list or tuple of InlineModelAdmin objects, as described below in the InlineModelAdmin section. For example, the following would return inlines without the default filtering based on add, change, and delete permissions:

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]

If you override this method, make sure that the returned inlines are instances of the classes defined in inlines or you might encounter a “Bad Request” error when adding related objects.

ModelAdmin.get_urls()

ModelAdminget_urls 方法返回ModelAdmin 将要用到的URLs,方式与URLconf 相同。因此,你可以用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 的布局,可以从admin/base_site.html 扩展︰

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

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

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

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

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

因为这通常不是你想要的,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

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

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

这个封装将保护self.my_view 免受未经授权的访问,并将运用django.views.decorators.cache.never_cache 装饰器以确保它不会被缓存,即使缓存中间件是活跃的。

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

url(r'^my_view/$', self.admin_site.admin_view(self.my_view, cacheable=True))
ModelAdmin.get_form(request, obj=None, **kwargs)

返回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(request, obj=None)

Deprecated since version 1.7: Use get_formsets_with_inlines() instead.

Yields InlineModelAdmins for use in admin add and change views.

For example if you wanted to display a particular inline only in the change view, you could override get_formsets as follows:

class MyModelAdmin(admin.ModelAdmin):
    inlines = [MyInline, SomeOtherInline]

    def get_formsets(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)
ModelAdmin.get_formsets_with_inlines(request, obj=None)
New in Django 1.7.

Yields (FormSet, InlineModelAdmin) pairs for use in admin add and change views.

For example if you wanted to display a particular inline only in the change view, you could override get_formsets_with_inlines as follows:

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)

The formfield_for_foreignkey method on a ModelAdmin allows you to override the default formfield for a foreign keys field. For example, to return a subset of objects for this foreign key field based on the user:

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)

This uses the HttpRequest instance to filter the Car foreign key field to only display the cars owned by the User instance.

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

Like the formfield_for_foreignkey method, the formfield_for_manytomany method can be overridden to change the default formfield for a many to many field. For example, if an owner can own multiple cars and cars can belong to multiple owners – a many to many relationship – you could filter the Car foreign key field to only display the cars owned by the 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)

Like the formfield_for_foreignkey and formfield_for_manytomany methods, the formfield_for_choice_field method can be overridden to change the default formfield for a field that has declared choices. For example, if the choices available to a superuser should be different than those available to regular staff, you could proceed as follows:

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)

Note

Any choices attribute set on the formfield will limited to the form field only. If the corresponding field on the model has choices set, the choices provided to the form must be a valid subset of those choices, otherwise the form submission will fail with a ValidationError when the model itself is validated before saving.

ModelAdmin.get_changelist(request, **kwargs)

Returns the Changelist class to be used for listing. By default, django.contrib.admin.views.main.ChangeList is used. By inheriting this class you can change the behavior of the listing.

ModelAdmin.get_changelist_form(request, **kwargs)

Returns a ModelForm class for use in the Formset on the changelist page. To use a custom form, for example:

from django import forms

class MyForm(forms.ModelForm):
    pass

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

Note

If you define the Meta.model attribute on a ModelForm, you must also define the Meta.fields attribute (or the Meta.exclude attribute). However, ModelAdmin ignores this value, overriding it with the ModelAdmin.list_editable attribute. The easiest solution is to omit the Meta.model attribute, since ModelAdmin will provide the correct model to use.

ModelAdmin.get_changelist_formset(request, **kwargs)

Returns a ModelFormSet class for use on the changelist page if list_editable is used. To use a custom formset, for example:

from django.forms.models 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)

Should return True if adding an object is permitted, False otherwise.

ModelAdmin.has_change_permission(request, obj=None)

Should return True if editing obj is permitted, False otherwise. If obj is None, should return True or False to indicate whether editing of objects of this type is permitted in general (e.g., False will be interpreted as meaning that the current user is not permitted to edit any object of this type).

ModelAdmin.has_delete_permission(request, obj=None)

Should return True if deleting obj is permitted, False otherwise. If obj is None, should return True or False to indicate whether deleting objects of this type is permitted in general (e.g., False will be interpreted as meaning that the current user is not permitted to delete any object of this type).

ModelAdmin.has_module_permission(request)
New in Django 1.8.

Should return True if displaying the module on the admin index page and accessing the module’s index page is permitted, False otherwise. Uses User.has_module_perms() by default. Overriding it does not restrict access to the add, change or delete views, has_add_permission(), has_change_permission(), and has_delete_permission() should be used for that.

ModelAdmin.get_queryset(request)

The get_queryset method on a ModelAdmin returns a QuerySet of all model instances that can be edited by the admin site. One use case for overriding this method is to show objects owned by the logged-in user:

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(queryset, per_page, orphans=0, allow_empty_first_page=True)

Returns an instance of the paginator to use for this view. By default, instantiates an instance of paginator.

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

Determines the HttpResponse for the add_view() stage.

response_add is called after the admin form is submitted and just after the object and all the related instances have been created and saved. You can override it to change the default behavior after the object has been created.

ModelAdmin.response_change(request, obj)

确定change_view() 阶段的HttpResponse

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

ModelAdmin.response_delete(request, obj_display, obj_id)
New in Django 1.7.

Determines the HttpResponse for the delete_view() stage.

response_delete is called after the object has been deleted. You can override it to change the default behavior after the object has been deleted.

obj_display is a string with the name of the deleted object.

obj_id is the serialized identifier used to retrieve the object to be deleted.

New in Django 1.8:

The obj_id parameter was added.

ModelAdmin.get_changeform_initial_data(request)
New in Django 1.7.

A hook for the initial data on admin change forms. By default, fields are given initial values from GET parameters. For instance, ?name=initial_value will set the name field’s initial value to be initial_value.

This method should return a dictionary in the form {'fieldname': 'fieldval'}:

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

Other methods

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

Django view for the model instance addition page. See note below.

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

Django view for the model instance edition page. See note below.

ModelAdmin.changelist_view(request, extra_context=None)

Django view for the model instances change list/actions page. See note below.

ModelAdmin.delete_view(request, object_id, extra_context=None)

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

ModelAdmin.history_view(request, object_id, extra_context=None)

Django view for the page that shows the modification history for a given model instance.

Unlike the hook-type ModelAdmin methods detailed in the previous section, these five methods are in reality designed to be invoked as Django views from the admin application URL dispatching handler to render the pages that deal with model instances CRUD operations. As a result, completely overriding these methods will significantly change the behavior of the admin application.

One common reason for overriding these methods is to augment the context data that is provided to the template that renders the view. In the following example, the change view is overridden so that the rendered template is provided some extra mapping data that would not otherwise be available:

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)

These views return TemplateResponse instances which allow you to easily customize the response data before rendering. For more details, see the TemplateResponse documentation.

ModelAdmin asset definitions

There are times where you would like add a bit of CSS and/or JavaScript to the add/change views. This can be accomplished by using a Media inner class on your ModelAdmin:

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

The staticfiles app prepends STATIC_URL (or MEDIA_URL if STATIC_URL is None) to any asset paths. The same rules apply as regular asset definitions on forms.

jQuery

Django admin JavaScript makes use of the jQuery library.

To avoid conflicts with user-supplied scripts or libraries, Django’s jQuery (version 1.11.2) is namespaced as django.jQuery. If you want to use jQuery in your own admin JavaScript without including a second copy, you can use the django.jQuery object on changelist and add/edit views.

Changed in Django 1.8:

The embedded jQuery has been upgraded from 1.9.1 to 1.11.2.

The ModelAdmin class requires jQuery by default, so there is no need to add jQuery to your ModelAdmin’s list of media resources unless you have a specific need. For example, if you require the jQuery library to be in the global namespace (for example when using third-party jQuery plugins) or if you need a newer version of jQuery, you will have to include your own copy.

Django provides both uncompressed and ‘minified’ versions of jQuery, as jquery.js and jquery.min.js respectively.

ModelAdmin and InlineModelAdmin have a media property that returns a list of Media objects which store paths to the JavaScript files for the forms and/or formsets. If DEBUG is True it will return the uncompressed versions of the various JavaScript files, including jquery.js; if not, it will return the ‘minified’ versions.

Adding custom validation to the admin

Adding custom validation of data in the admin is quite easy. The automatic admin interface reuses django.forms, and the ModelAdmin class gives you the ability define your own form:

class ArticleAdmin(admin.ModelAdmin):
    form = MyArticleAdminForm

MyArticleAdminForm can be defined anywhere as long as you import where needed. Now within your form you can add your own custom validation for any field:

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

It is important you use a ModelForm here otherwise things can break. See the forms documentation on custom validation and, more specifically, the model form validation notes for more information.

InlineModelAdmin objects

class InlineModelAdmin
class TabularInline
class StackedInline

此管理界面能够在一个界面编辑多个Model。These are called inlines. Suppose you have these two models:

from django.db import models

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

class Book(models.Model):
   author = models.ForeignKey(Author)
   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:You add inlines to a model by specifying them in a ModelAdmin.inlines:

from django.contrib import admin

class BookInline(admin.TabularInline):
    model = Book

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

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

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

InlineModelAdmin options

InlineModelAdmin shares many of the same features as ModelAdmin, and adds some of its own (the shared features are actually defined in the BaseModelAdmin superclass). The shared features are:

The InlineModelAdmin class adds:

InlineModelAdmin.model

The model which the inline is using. This is required.

InlineModelAdmin.fk_name

The name of the foreign key on the model. In most cases this will be dealt with automatically, but fk_name must be specified explicitly if there are more than one foreign key to the same parent model.

InlineModelAdmin.formset

This defaults to BaseInlineFormSet. Using your own formset can give you many possibilities of customization. Inlines are built around model formsets.

InlineModelAdmin.form

The value for form defaults to ModelForm. This is what is passed through to inlineformset_factory() when creating the formset for this inline.

Warning

When writing custom validation for InlineModelAdmin forms, be cautious of writing validation that relies on features of the parent model. If the parent model fails to validate, it may be left in an inconsistent state as described in the warning in Validation on a ModelForm.

InlineModelAdmin.extra

This controls the number of extra forms the formset will display in addition to the initial forms. See the formsets documentation for more information.

For users with JavaScript-enabled browsers, an “Add another” link is provided to enable any number of additional inlines to be added in addition to those provided as a result of the extra argument.

The dynamic link will not appear if the number of currently displayed forms exceeds max_num, or if the user does not have JavaScript enabled.

InlineModelAdmin.get_extra() also allows you to customize the number of extra forms.

InlineModelAdmin.max_num

This controls the maximum number of forms to show in the inline. This doesn’t directly correlate to the number of objects, but can if the value is small enough. See Limiting the number of editable objects for more information.

InlineModelAdmin.get_max_num() also allows you to customize the maximum number of extra forms.

InlineModelAdmin.min_num
New in Django 1.7.

This controls the minimum number of forms to show in the inline. See modelformset_factory() for more information.

InlineModelAdmin.get_min_num() also allows you to customize the minimum number of displayed forms.

InlineModelAdmin.raw_id_fields

By default, Django’s admin uses a select-box interface (<select>) for fields that are ForeignKey. Sometimes you don’t want to incur the overhead of having to select all the related instances to display in the drop-down.

raw_id_fields is a list of fields you would like to change into a Input widget for either a ForeignKey or ManyToManyField:

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

The template used to render the inline on the page.

InlineModelAdmin.verbose_name

An override to the verbose_name found in the model’s inner Meta class.

InlineModelAdmin.verbose_name_plural

An override to the verbose_name_plural found in the model’s inner Meta class.

InlineModelAdmin.can_delete

Specifies whether or not inline objects can be deleted in the inline. Defaults to True.

New in Django 1.8.

Specifies whether or not inline objects that can be changed in the admin have a link to the change form. Defaults to False.

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

Returns a BaseInlineFormSet class for use in admin add/change views. See the example for ModelAdmin.get_formsets_with_inlines.

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

Returns the number of extra inline forms to use. By default, returns the InlineModelAdmin.extra attribute.

Override this method to programmatically determine the number of extra inline forms. For example, this may be based on the model instance (passed as the keyword argument 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)

Returns the maximum number of extra inline forms to use. By default, returns the InlineModelAdmin.max_num attribute.

Override this method to programmatically determine the maximum number of inline forms. For example, this may be based on the model instance (passed as the keyword argument obj):

class BinaryTreeAdmin(admin.TabularInline):
    model = BinaryTree

    def get_max_num(self, request, obj=None, **kwargs):
        max_num = 10
        if obj.parent:
            return max_num - 5
        return max_num
InlineModelAdmin.get_min_num(request, obj=None, **kwargs)
New in Django 1.7.

Returns the minimum number of inline forms to use. By default, returns the InlineModelAdmin.min_num attribute.

Override this method to programmatically determine the minimum number of inline forms. For example, this may be based on the model instance (passed as the keyword argument obj).

Working with a model with two or more foreign keys to the same parent model

It is sometimes possible to have more than one foreign key to the same model. Take this model for instance:

from django.db import models

class Friendship(models.Model):
    to_person = models.ForeignKey(Person, related_name="friends")
    from_person = models.ForeignKey(Person, related_name="from_friends")

If you wanted to display an inline on the Person admin add/change pages you need to explicitly define the foreign key since it is unable to do so automatically:

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,
    ]

Working with many-to-many models

By default, admin widgets for many-to-many relations will be displayed on whichever model contains the actual reference to the ManyToManyField. Depending on your ModelAdmin definition, each many-to-many field in your model will be represented by a standard HTML <select multiple>, a horizontal or vertical filter, or a raw_id_admin widget. However, it is also possible to replace these widgets with inlines.

Suppose we have the following models:

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

If you want to display many-to-many relations using an inline, you can do so by defining an InlineModelAdmin object for the relationship:

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

There are two features worth noting in this example.

Firstly - the MembershipInline class references Group.members.through. The through attribute is a reference to the model that manages the many-to-many relation. This model is automatically created by Django when you define a many-to-many field.

Secondly, the GroupAdmin must manually exclude the members field. Django displays an admin widget for a many-to-many field on the model that defines the relation (in this case, Group). If you want to use an inline model to represent the many-to-many relationship, you must tell Django’s admin to not display this widget - otherwise you will end up with two widgets on your admin page for managing the relation.

In all other respects, the InlineModelAdmin is exactly the same as any other. You can customize the appearance using any of the normal ModelAdmin properties.

Working with many-to-many intermediary models

当您使用ManyToManyFieldthrough参数指定中介模型时,admin将不会默认显示窗口小部件。This is because each instance of that intermediary model requires more information than could be displayed in a single widget, and the layout required for multiple widgets will vary depending on the intermediate model.

但是,我们仍然希望能够在内联里编辑该信息。幸运的是,这用内联管理模型很容易做到Suppose we have the following models:

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)
    group = models.ForeignKey(Group)
    date_joined = models.DateField()
    invite_reason = models.CharField(max_length=64)

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

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

This simple example uses the default InlineModelAdmin values for the Membership model, and limits the extra add forms to one. This could be customized using any of the options available to InlineModelAdmin classes.

Now create admin views for the Person and Group models:

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

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

Finally, register your Person and Group models with the admin site:

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

Now your admin site is set up to edit Membership objects inline from either the Person or the Group detail pages.

Using generic relations as an inline

It is possible to use an inline with generically related objects. 假设您有以下模型:

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)
    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 Image instance on the Product add/change views you can use GenericTabularInline or GenericStackedInline (both subclasses of GenericInlineModelAdmin) provided by admin, they implement tabular and stacked visual layouts for the forms representing the inline objects respectively just like their non-generic counterparts and behave just like any other inline. In your admin.py for this example app:

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)

See the contenttypes documentation for more specific information.

重写 admin 模板

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

设置项目的Admin模板目录

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

如要覆盖一个或多个模板,首先在你的项目的templates 目录中创建一个admin 目录。它可以是你在TEMPLATES 设置的DjangoTemplates 后端的DIRS 选项中指定的任何目录。如果你已经自定义'loaders' 选项,请确保'django.template.loaders.filesystem.Loader' 出现在 '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 my_app, we would copy contrib/admin/templates/admin/change_list.html to the templates/admin/my_app/ directory of our project, and make any necessary changes.

If we wanted to add a tool to the change list view for only a specific model named ‘Page’, we would copy that same file to the templates/admin/my_app/page directory of our project.

Overriding vs. replacing an admin template

Because of the modular design of the admin templates, it is usually neither necessary nor advisable to replace an entire template. It is almost always better to override only the section of the template which you need to change.

To continue the example above, we want to add a new link next to the History tool for the Page model. After looking at change_form.html we determine that we only need to override the object-tools-items block. Therefore here is our new 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 %}

And that’s it! If we placed this file in the templates/admin/my_app directory, our link would appear on the change form for all models within 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 页面特别有用。

注意

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

Root and login 模板

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

AdminSite objects

class AdminSite(name='admin')

Django 的一个Admin 站点通过django.contrib.admin.sites.AdminSite 的一个实例表示;默认创建的这个类实例是django.contrib.admin.site,你可以通过它注册自己的模型和ModelAdmin 实例。

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

AdminSite attributes

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

AdminSite.site_header
New in Django 1.7.

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

AdminSite.site_title
New in Django 1.7.

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

AdminSite.site_url
New in Django 1.8.

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

AdminSite.index_title
New in Django 1.7.

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

AdminSite.index_template

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

AdminSite.app_index_template

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

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 methods

AdminSite.each_context(request)
New in Django 1.7.

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

包含以下变量和默认值:

Changed in Django 1.8:

添加request 参数和has_permission 变量。

AdminSite.has_permission(request)

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

绑定AdminSite

设置Django Admin 的最后一步是放置你的AdminSite 到你的URLconf 中。通过指向给定的URL 到AdminSite.urls 方法来执行此操作。

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

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

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

Customizing the 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 include, url

from myapp.admin import admin_site

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

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

相同URLconf 中有多个Admin 站点

在Django 构建的同一Web 站点上创建Admin 站点的多个实例非常容易。只需要创建AdminSite 的多个实例并将每个实例放置在不同的URL 下。

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

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

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

AdminSite 实例的构造函数中接受一个单一参数用做它们的名字,可以是任何你喜欢的东西。此参数将成为反向解析它们 时URL 名称的前缀。只有在你使用多个AdminSite 时它才是必要的。

Adding views to admin sites

Just like ModelAdmin, AdminSite provides a get_urls() method that can be overridden to define additional views for the site. To add a new view to your admin site, extend the base get_urls() method to include a pattern for your new view.

Note

Any view you render that uses the admin templates, or extends the base admin template, should set request.current_app before rendering the template. 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.

Changed in Django 1.8:

In previous versions of Django, you had to provide the current_app argument to RequestContext or Context when rendering the template.

加入一个密码重置的特性

想admin site加入密码重置功能只需要在url配置文件中简单加入几行代码即可。具体操作就是加入下面四个正则规则。

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

(This assumes you’ve added the admin at admin/ and requires that you put the URLs starting with ^admin/ before the line that includes the admin app itself).

The presence of the admin_password_reset named URL will cause a “forgotten your password?” link to appear on the default admin log-in page under the password box.

反向解析Admin 的URL

AdminSite 部署后,该站点所提供的视图都可以使用Django 的URL 反向解析系统访问。

AdminSite 提供以下命名URL:

Page URL name Parameters
Index index  
Logout logout  
Password change password_change  
Password change done password_change_done  
i18n JavaScript jsi18n  
Application index page app_list app_label
Redirect to object’s page view_on_site content_type_id, object_id

每个ModelAdmin 实例还将提供额外的命名URL:

Page URL name Parameters
Changelist {{ app_label }}_{{ model_name }}_changelist  
Add {{ app_label }}_{{ model_name }}_add  
History {{ app_label }}_{{ model_name }}_history object_id
Delete {{ app_label }}_{{ model_name }}_delete object_id
Change {{ app_label }}_{{ model_name }}_change object_id

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

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

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

This will find the first registered instance of the admin application (whatever the instance name), and resolve to the view for changing poll.Choice instances in that instance.

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

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

有关更多详细信息,请参阅反向解析名称空间URL 的文档。

为了让模板中反向解析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 名称的最后部分。opts 变量可以是任何具有app_labelmodel_name 属性的对象,通常由Admin 视图为当前的模型提供。