One of the most powerful parts of Django is the automatic admin interface. It
reads metadata in your model to provide a powerful and production-ready
interface that content producers can immediately use to start adding content to
the site. In this document, we discuss how to activate, use and customize
Django’s admin interface.

The ModelAdmin class is the representation of a model in the admin
interface. Usually, these are stored in a file named admin.py in your
application. Let’s take a look at a very simple example of
the ModelAdmin:

In the preceding example, the ModelAdmin class doesn’t define any
custom values (yet). As a result, the default admin interface will be
provided. If you are happy with the default admin interface, you don’t
need to define a ModelAdmin object at all – you can register the
model class without providing a ModelAdmin description. The
preceding example could be simplified to:

This function attempts to import an admin module in each installed
application. Such modules are expected to register models with the admin.

Typically you won’t need to call this function directly as
AdminConfig calls it when Django starts.

If you are using a custom AdminSite, it is common to import all of the
ModelAdmin subclasses into your code and register them to the custom
AdminSite. In that case, in order to disable auto-discovery, you should
put 'django.contrib.admin.apps.SimpleAdminConfig' instead of
'django.contrib.admin' in your INSTALLED_APPS setting.

If you need to achieve simple changes in the layout of fields in the forms
of the “add” and “change” pages like only showing a subset of the available
fields, modifying their order or grouping them in rows you can use the
fields option (for more complex layout needs see the
fieldsets option described in the next section). For
example, you could define a simpler version of the admin form for the
django.contrib.flatpages.models.FlatPage model as follows:

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

In the above example, only the fields url, title and content
will be displayed, sequentially, in the form. fields can contain
values defined in ModelAdmin.readonly_fields to be displayed as
read-only.

The fields option, unlike list_display, may only
contain names of fields on the model or the form specified by
form. It may contain callables only if they are listed
in readonly_fields.

To display multiple fields on the same line, wrap those fields in their own
tuple. In this example, the url and title fields will display on the
same line and the content field will be displayed below them in its
own line:

This fields option should not be confused with the fields
dictionary key that is within the fieldsets option,
as described in the next section.

If neither fields nor fieldsets options are present,
Django will default to displaying each field that isn’t an AutoField and
has editable=True, in a single fieldset, in the same order as the fields
are defined in the model.

Set fieldsets to control the layout of admin “add” and “change” pages.

fieldsets is a list of two-tuples, in which each two-tuple represents a
<fieldset> on the admin form page. (A <fieldset> is a “section” of
the form.)

The two-tuples are in the format (name,field_options), where name
is a string representing the title of the fieldset and field_options is
a dictionary of information about the fieldset, including a list of fields
to be displayed in it.

If neither fieldsets nor fields options are present,
Django will default to displaying each field that isn’t an AutoField and
has editable=True, in a single fieldset, in the same order as the fields
are defined in the model.

The field_options dictionary can have the following keys:

fields

A tuple of field names to display in this fieldset. This key is
required.

Example:

{'fields':('first_name','last_name','address','city','state'),}

As with the fields option, to display multiple
fields on the same line, wrap those fields in their own tuple. In this
example, the first_name and last_name fields will display on
the same line:

{'fields':(('first_name','last_name'),'address','city','state'),}

fields can contain values defined in
readonly_fields to be displayed as read-only.

If you add the name of a callable to fields, the same rule applies
as with the fields option: the callable must be
listed in readonly_fields.

classes

A list containing extra CSS classes to apply to the fieldset.

Example:

{'classes':('wide','extrapretty'),}

Two useful classes defined by the default admin site stylesheet are
collapse and wide. Fieldsets with the collapse style
will be initially collapsed in the admin and replaced with a small
“click to expand” link. Fieldsets with the wide style will be
given extra horizontal space.

description

A string of optional extra text to be displayed at the top of each
fieldset, under the heading of the fieldset. This string is not
rendered for TabularInline due to its
layout.

Note that this value is not HTML-escaped when it’s displayed in
the admin interface. This lets you include HTML if you so desire.
Alternatively you can use plain text and
django.utils.html.escape() to escape any HTML special
characters.

By default, a ManyToManyField is displayed in
the admin site with a <selectmultiple>. However, multiple-select boxes
can be difficult to use when selecting many items. Adding a
ManyToManyField to this list will instead use
a nifty unobtrusive JavaScript “filter” interface that allows searching
within the options. The unselected and selected options appear in two boxes
side by side. See filter_vertical to use a vertical
interface.

By default a ModelForm is dynamically created for your model. It is
used to create the form presented on both the add/change pages. You can
easily provide your own ModelForm to override any default form behavior
on the add/change pages. Alternatively, you can customize the default
form rather than specifying an entirely new one by using the
ModelAdmin.get_form() method.

If you define the Meta.model attribute on a
ModelForm, you must also define the
Meta.fields attribute (or the Meta.exclude attribute). However,
since the admin has its own way of defining fields, the Meta.fields
attribute will be ignored.

If the ModelForm is only going to be used for the admin, the easiest
solution is to omit the Meta.model attribute, since ModelAdmin
will provide the correct model to use. Alternatively, you can set
fields=[] in the Meta class to satisfy the validation on the
ModelForm.

Note

If your ModelForm and ModelAdmin both define an exclude
option then ModelAdmin takes precedence:

This provides a quick-and-dirty way to override some of the
Field options for use in the admin.
formfield_overrides is a dictionary mapping a field class to a dict of
arguments to pass to the field at construction time.

Since that’s a bit abstract, let’s look at a concrete example. The most
common use of formfield_overrides is to add a custom widget for a
certain type of field. So, imagine we’ve written a RichTextEditorWidget
that we’d like to use for large text fields instead of the default
<textarea>. Here’s how we’d do that:

Note that the key in the dictionary is the actual field class, not a
string. The value is another dictionary; these arguments will be passed to
the form field’s __init__() method. See The Forms API for
details.

Warning

If you want to use a custom widget with a relation field (i.e.
ForeignKey or
ManyToManyField), make sure you haven’t
included that field’s name in raw_id_fields or radio_fields.

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.

If the field is a ForeignKey, Django will display the
__str__() (__unicode__() on Python 2) of the related object.

ManyToManyField fields aren’t supported, because that would
entail executing a separate SQL statement for each row in the table.
If you want to do this nonetheless, give your model a custom method,
and add that method’s name to list_display. (See below for more
on custom methods in list_display.)

If the field is a BooleanField or NullBooleanField, Django
will display a pretty “on” or “off” icon instead of True or
False.

If the string given is a method of the model, ModelAdmin or a
callable, Django will HTML-escape the output by default. If you’d
rather not escape the output of the method, give the method an
allow_tags attribute whose value is True. However, to avoid an
XSS vulnerability, you should use format_html()
to escape user-provided inputs.

If the string given is a method of the model, ModelAdmin or a
callable that returns True or False Django will display a pretty
“on” or “off” icon if you give the method a boolean attribute
whose value is True.

The above will tell Django to order by the first_name field when
trying to sort by colored_first_name in the admin.

To indicate descending order with admin_order_field you can use a
hyphen prefix on the field name. Using the above example, this would
look like:

colored_first_name.admin_order_field='-first_name'

Elements of list_display can also be properties. Please note however,
that due to the way properties work in Python, setting
short_description on a property is only possible when using the
property() function and not with the @property decorator.

For example:

classPerson(models.Model):first_name=models.CharField(max_length=50)last_name=models.CharField(max_length=50)defmy_property(self):returnself.first_name+' '+self.last_namemy_property.short_description="Full name of the person"full_name=property(my_property)classPersonAdmin(admin.ModelAdmin):list_display=('full_name',)

The field names in list_display will also appear as CSS classes in
the HTML output, in the form of column-<field_name> on each <th>
element. This can be used to set column widths in a CSS file for example.

Django will try to interpret every element of list_display in this
order:

A field of the model.

A callable.

A string representing a ModelAdmin attribute.

A string representing a model attribute.

For example if you have first_name as a model field and
as a ModelAdmin attribute, the model field will be used.

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:

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.

Set list_filter to activate filters in the right sidebar of the change
list page of the admin, as illustrated in the following screenshot:

list_filter should be a list or tuple of elements, where each element
should be of one of the following types:

a field name, where the specified field should be either a
BooleanField, CharField, DateField, DateTimeField,
IntegerField, ForeignKey or ManyToManyField, for example:

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

Field names in list_filter can also span relations
using the __ lookup, for example:

classPersonAdmin(admin.UserAdmin):list_filter=('company__name',)

a class inheriting from django.contrib.admin.SimpleListFilter,
which you need to provide the title and parameter_name
attributes to and override the lookups and queryset methods,
e.g.:

fromdatetimeimportdatefromdjango.contribimportadminfromdjango.utils.translationimportugettext_lazyas_classDecadeBornListFilter(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'deflookups(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')),)defqueryset(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.ifself.value()=='80s':returnqueryset.filter(birthday__gte=date(1980,1,1),birthday__lte=date(1989,12,31))ifself.value()=='90s':returnqueryset.filter(birthday__gte=date(1990,1,1),birthday__lte=date(1999,12,31))classPersonAdmin(admin.ModelAdmin):list_filter=(DecadeBornListFilter,)

Note

As a convenience, the HttpRequest object is passed to the
lookups and queryset methods, for example:

Also as a convenience, the ModelAdmin object is passed to
the lookups method, for example if you want to base the
lookups on the available data:

classAdvancedDecadeBornListFilter(DecadeBornListFilter):deflookups(self,request,model_admin):""" Only show the lookups if there actually is anyone born in the corresponding decades. """qs=model_admin.get_queryset(request)ifqs.filter(birthday__gte=date(1980,1,1),birthday__lte=date(1989,12,31)).exists():yield('80s',_('in the eighties'))ifqs.filter(birthday__gte=date(1990,1,1),birthday__lte=date(1999,12,31)).exists():yield('90s',_('in the nineties'))

a tuple, where the first element is a field name and the second
element is a class inheriting from
django.contrib.admin.FieldListFilter, for example:

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.

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. When
value is set to False, Django will look at list_display and call
select_related() if any ForeignKey is present.

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:

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

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:

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 an Input widget for either a ForeignKey or
ManyToManyField:

classArticleAdmin(admin.ModelAdmin):raw_id_fields=("newspaper",)

The raw_id_fieldsInput widget should contain a primary key if the
field is a ForeignKey or a comma separated list of values if the field
is a ManyToManyField. The raw_id_fields widget shows a magnifying
glass button next to the field which allows users to search for and select
a value:

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

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:

fromdjango.contribimportadminfromdjango.utils.htmlimportformat_html_joinfromdjango.utils.safestringimportmark_safeclassPersonAdmin(admin.ModelAdmin):readonly_fields=('address_report',)defaddress_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 linebreakreturnformat_html_join(mark_safe('<br/>'),'{}',((line,)forlineininstance.get_full_address()),)or"<span class='errors'>I can't determine this address.</span>"# short_description functions like a model field's verbose_nameaddress_report.short_description="Address"# in this example, we have used HTML tags in the outputaddress_report.allow_tags=True

Set search_fields to enable a search box on the admin change list page.
This should be set to a list of field names that will be searched whenever
somebody submits a search query in that text box.

These fields should be some kind of text field, such as CharField or
TextField. You can also perform a related lookup on a ForeignKey or
ManyToManyField with the lookup API “follow” notation:

search_fields=['foreign_key__related_fieldname']

For example, if you have a blog entry with an author, the following
definition would enable search blog entries by the email address of the
author:

search_fields=['user__email']

When somebody does a search in the admin search box, Django splits the
search query into words and returns all objects that contain each of the
words, case insensitive, where each word must be in at least one of
search_fields. For example, if search_fields is set to
['first_name','last_name'] and a user searches for johnlennon,
Django will do the equivalent of this SQL WHERE clause:

This query is more efficient than the normal '%john%' query,
because the database only needs to check the beginning of a column’s
data, rather than seeking through the entire column’s data. Plus, if
the column has an index on it, some databases may be able to use the
index for this query, even though it’s a LIKE query.

=

Matches exactly, case-insensitive. For example, if
search_fields is set to ['=first_name','=last_name'] and
a user searches for johnlennon, Django will do the equivalent
of this SQL WHERE clause:

Set show_full_result_count to control whether the full count of objects
should be displayed on a filtered admin page (e.g. 99results(103total)).
If this option is set to False, a text like 99results(Showall)
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.

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. Here you can do any pre- or post-save operations.

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.

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.

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.

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.

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.

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.

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.

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:

The get_urls method on a ModelAdmin returns the URLs to be used for
that ModelAdmin in the same way as a URLconf. Therefore you can extend
them as documented in URL dispatcher:

classMyModelAdmin(admin.ModelAdmin):defget_urls(self):urls=super(MyModelAdmin,self).get_urls()my_urls=[url(r'^my_view/$',self.my_view),]returnmy_urls+urlsdefmy_view(self,request):# ...context=dict(# Include common variables for rendering the admin template.self.each_context(request),# Anything else you want in the context...key=value,)returnTemplateResponse(request,"sometemplate.html",context)

If you want to use the admin layout, extend from admin/base_site.html:

{%extends"admin/base_site.html"%}{%blockcontent%}
...
{%endblock%}

Note

Notice that the custom patterns are included before the regular admin
URLs: the admin URL patterns are very permissive and will match nearly
anything, so you’ll usually want to prepend your custom URLs to the
built-in ones.

In this example, my_view will be accessed at
/admin/myapp/mymodel/my_view/ (assuming the admin URLs are included
at /admin/.)

However, the self.my_view function registered above suffers from two
problems:

It will not perform any permission checks, so it will be accessible
to the general public.

It will not provide any header details to prevent caching. This means
if the page retrieves data from the database, and caching middleware is
active, the page could show outdated information.

Since this is usually not what you want, Django provides a convenience
wrapper to check permissions and mark the view as non-cacheable. This
wrapper is AdminSite.admin_view() (i.e. self.admin_site.admin_view
inside a ModelAdmin instance); use it like so:

The base implementation uses modelform_factory()
to subclass form, modified by attributes such as fields
and exclude. So, for example, if you wanted to offer additional
fields to superusers, you could swap in a different base form like so:

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:

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:

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:

classMyModelAdmin(admin.ModelAdmin):defformfield_for_choice_field(self,db_field,request,**kwargs):ifdb_field.name=="status":kwargs['choices']=(('accepted','Accepted'),('denied','Denied'),)ifrequest.user.is_superuser:kwargs['choices']+=(('ready','Ready for deployment'),)returnsuper(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.

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.

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

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

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:

Keyword arguments allow you to change the message level, add extra CSS
tags, or fail silently if the contrib.messages framework is not
installed. These keyword arguments match those for
django.contrib.messages.add_message(), see that function’s
documentation for more details. One difference is that the level may be
passed as a string label in addition to integer/constant.

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.

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

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'}:

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:

classMyModelAdmin(admin.ModelAdmin):# A template for a very customized change view:change_form_template='admin/myapp/extras/openstreetmap_change_form.html'defget_osm_info(self):# ...passdefchange_view(self,request,object_id,form_url='',extra_context=None):extra_context=extra_contextor{}extra_context['osm_data']=self.get_osm_info()returnsuper(MyModelAdmin,self).change_view(request,object_id,form_url,extra_context=extra_context)

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.

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.

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.

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:

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 <selectmultiple>, a horizontal or vertical filter, or a
raw_id_admin widget. However, it is also possible to replace these
widgets with inlines.

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.

Note that when using this technique the
m2m_changed signals aren’t triggered. This
is because as far as the admin is concerned, through is just a model with
two foreign key fields rather than a many-to-many 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.

When you specify an intermediary model using the through argument to a
ManyToManyField, the admin will not display a
widget by default. 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.

However, we still want to be able to edit that information inline. Fortunately,
this is easy to do with inline admin models. Suppose we have the following
models:

The first step in displaying this intermediate model in the admin is to
define an inline class for the Membership model:

classMembershipInline(admin.TabularInline):model=Membershipextra=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.

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:

It is relatively easy to override many of the templates which the admin module
uses to generate the various pages of an admin site. You can even override a
few of these templates for a specific app, or a specific model.

The admin template files are located in the contrib/admin/templates/admin
directory.

In order to override one or more of them, first create an admin directory
in your project’s templates directory. This can be any of the directories
you specified in the DIRS option of the
DjangoTemplates backend in the TEMPLATES setting. 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.

Within this admin directory, create sub-directories named after your app.
Within these app subdirectories create sub-directories named after your models.
Note, that the admin app will lowercase the model name when looking for the
directory, so make sure you name the directory in all lowercase if you are
going to run your app on a case-sensitive filesystem.

To override an admin template for a specific app, copy and edit the template
from the django/contrib/admin/templates/admin directory, and save it to one
of the directories you just created.

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.

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 :

Not every template in contrib/admin/templates/admin may be overridden per
app or per model. The following can:

app_index.html

change_form.html

change_list.html

delete_confirmation.html

object_history.html

For those templates that cannot be overridden in this way, you may still
override them for your entire project. Just place the new version in your
templates/admin directory. This is particularly useful to create custom 404
and 500 pages.

Note

Some of the admin templates, such as change_list_results.html are used
to render custom inclusion tags. These may be overridden, but in such cases
you are probably better off creating your own version of the tag in
question and giving it a different name. That way you can use it
selectively.

A Django administrative site is represented by an instance of
django.contrib.admin.sites.AdminSite; by default, an instance of
this class is created as django.contrib.admin.site and you can
register your models and ModelAdmin instances with it.

When constructing an instance of an AdminSite, you can provide
a unique instance name using the name argument to the constructor. This
instance name is used to identify the instance, especially when
reversing admin URLs. If no instance name is
provided, a default instance name of admin will be used.
See Customizing the AdminSite class for an example of customizing the
AdminSite class.

If you’d like to set up your own admin site with custom behavior, you’re free
to subclass AdminSite and override or add anything you like. Then, simply
create an instance of your AdminSite subclass (the same way you’d
instantiate any other Python class) and register your models and
ModelAdmin subclasses with it instead of with the default site. Finally,
update myproject/urls.py to reference your AdminSite subclass.

Note that you may not want autodiscovery of admin modules when using your
own AdminSite instance since you will likely be importing all the per-app
admin modules in your myproject.admin module. This means you need to
put 'django.contrib.admin.apps.SimpleAdminConfig' instead of
'django.contrib.admin' in your INSTALLED_APPS setting.

It’s easy to create multiple instances of the admin site on the same
Django-powered Web site. Just create multiple instances of AdminSite and
root each one at a different URL.

In this example, the URLs /basic-admin/ and /advanced-admin/ feature
separate versions of the admin site – using the AdminSite instances
myproject.admin.basic_site and myproject.admin.advanced_site,
respectively:

AdminSite instances take a single argument to their constructor, their
name, which can be anything you like. This argument becomes the prefix to the
URL names for the purposes of reversing them. This
is only necessary if you are using more than one AdminSite.

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.

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.

If you want to find a URL in a specific admin instance, provide the name of
that instance as a current_app hint to the reverse call. For example,
if you specifically wanted the admin view from the admin instance named
custom, you would need to call:

The action in the examples above match the last part of the URL names for
ModelAdmin instances described above. The opts variable can be any
object which has an app_label and model_name attributes and is usually
supplied by the admin views for the current model.

This decorator is used on the admin views that require authorization. A
view decorated with this function will having the following behavior:

If the user is logged in, is a staff member (User.is_staff=True), and
is active (User.is_active=True), execute the view normally.

Otherwise, the request will be redirected to the URL specified by the
login_url parameter, with the originally requested path in a query
string variable specified by redirect_field_name. For example:
/admin/login/?next=/admin/polls/question/3/.

This document is for Django's development version, which can be significantly different from previous releases. For older releases, use the version selector floating in the bottom right corner of this page.