12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235 |
- .. _ref-contrib-admin:
- =====================
- The Django admin site
- =====================
- .. module:: django.contrib.admin
- :synopsis: Django's admin site.
- 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.
- .. admonition:: Note
- The admin site has been refactored significantly since Django 0.96. This
- document describes the newest version of the admin site, which allows for
- much richer customization. If you follow the development of Django itself,
- you may have heard this described as "newforms-admin."
- Overview
- ========
- There are five steps in activating the Django admin site:
- 1. Add ``django.contrib.admin`` to your ``INSTALLED_APPS`` setting.
- 2. Determine which of your application's models should be editable in the
- admin interface.
- 3. For each of those models, optionally create a ``ModelAdmin`` class that
- encapsulates the customized admin functionality and options for that
- particular model.
- 4. Instantiate an ``AdminSite`` and tell it about each of your models and
- ``ModelAdmin`` classes.
- 5. Hook the ``AdminSite`` instance into your URLconf.
- Other topics
- ------------
- .. toctree::
- :maxdepth: 1
- actions
- ``ModelAdmin`` objects
- ======================
- The ``ModelAdmin`` class is the representation of a model in the admin
- interface. 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``::
- from django.contrib import admin
- from myproject.myapp.models import Author
- class AuthorAdmin(admin.ModelAdmin):
- pass
- admin.site.register(Author, AuthorAdmin)
- .. admonition:: Do you need a ``ModelAdmin`` object at all?
- 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::
- from django.contrib import admin
- from myproject.myapp.models import Author
- admin.site.register(Author)
- ``ModelAdmin`` Options
- ----------------------
- The ``ModelAdmin`` is very flexible. It has several options for dealing with
- customizing the interface. All options are defined on the ``ModelAdmin``
- subclass::
- class AuthorAdmin(admin.ModelAdmin):
- date_hierarchy = 'pub_date'
- ``date_hierarchy``
- ~~~~~~~~~~~~~~~~~~
- Set ``date_hierarchy`` to the name of a ``DateField`` or ``DateTimeField`` in
- your model, and the change list page will include a date-based drilldown
- navigation by that field.
- Example::
- date_hierarchy = 'pub_date'
- ``form``
- ~~~~~~~~
- 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.
- For an example see the section `Adding custom validation to the admin`_.
- ``fieldsets``
- ~~~~~~~~~~~~~
- 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.
- A full example, taken from the ``django.contrib.flatpages.FlatPage`` model::
- class FlatPageAdmin(admin.ModelAdmin):
- fieldsets = (
- (None, {
- 'fields': ('url', 'title', 'content', 'sites')
- }),
- ('Advanced options', {
- 'classes': ('collapse',),
- 'fields': ('enable_comments', 'registration_required', 'template_name')
- }),
- )
- This results in an admin page that looks like:
- .. image:: _images/flatfiles_admin.png
- If ``fieldsets`` isn't given, 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'),
- }
- 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'),
- }
- * ``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.
- 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.
- ``fields``
- ~~~~~~~~~~
- Use this option as an alternative to ``fieldsets`` if the layout does not
- matter and if you want to only show a subset of the available fields in the
- form. For example, you could define a simpler version of the admin form for
- the ``django.contrib.flatpages.FlatPage`` model as follows::
- class FlatPageAdmin(admin.ModelAdmin):
- fields = ('url', 'title', 'content')
- In the above example, only the fields 'url', 'title' and 'content' will be
- displayed, sequentially, in the form.
- .. admonition:: Note
- This ``fields`` option should not be confused with the ``fields``
- dictionary key that is within the ``fieldsets`` option, as described in
- the previous section.
- ``exclude``
- ~~~~~~~~~~~
- This attribute, if given, should be a list of field names to exclude from the
- form.
- For example, let's consider the following model::
- class Author(models.Model):
- name = models.CharField(max_length=100)
- title = models.CharField(max_length=3)
- birth_date = models.DateField(blank=True, null=True)
- If you want a form for the ``Author`` model that includes only the ``name``
- and ``title`` fields, you would specify ``fields`` or ``exclude`` like this::
- class AuthorAdmin(admin.ModelAdmin):
- fields = ('name', 'title')
- class AuthorAdmin(admin.ModelAdmin):
- exclude = ('birth_date',)
- Since the Author model only has three fields, ``name``, ``title``, and
- ``birth_date``, the forms resulting from the above declarations will contain
- exactly the same fields.
- ``filter_horizontal``
- ~~~~~~~~~~~~~~~~~~~~~
- Use a nifty unobtrusive JavaScript "filter" interface instead of the
- usability-challenged ``<select multiple>`` in the admin form. The value is a
- list of fields that should be displayed as a horizontal filter interface. See
- ``filter_vertical`` to use a vertical interface.
- ``filter_vertical``
- ~~~~~~~~~~~~~~~~~~~
- Same as ``filter_horizontal``, but is a vertical display of the filter
- interface.
- ``list_display``
- ~~~~~~~~~~~~~~~~
- Set ``list_display`` to control which fields are displayed on the change list
- page of the admin.
- Example::
- list_display = ('first_name', 'last_name')
- If you don't set ``list_display``, the admin site will display a single column
- that displays the ``__unicode__()`` representation of each object.
- You have four possible values that can be used in ``list_display``:
- * A field of the model. For example::
- class PersonAdmin(admin.ModelAdmin):
- list_display = ('first_name', 'last_name')
- * A callable that accepts one parameter for the model instance. For
- example::
- 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,)
- * A string representing an attribute on the ``ModelAdmin``. This behaves
- same as the callable. For example::
- 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'
- * A string representing an attribute on the model. This behaves almost
- the same as the callable, but ``self`` in this context is the model
- instance. Here's a full model example::
- 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')
- A few special cases to note about ``list_display``:
- * If the field is a ``ForeignKey``, Django will display the
- ``__unicode__()`` 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``.
- Here's a full example model::
- 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 '<span style="color: #%s;">%s %s</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')
- * 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``.
- Here's a full example model::
- 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] == 5
- born_in_fifties.boolean = True
- class PersonAdmin(admin.ModelAdmin):
- list_display = ('name', 'born_in_fifties')
- * The ``__str__()`` and ``__unicode__()`` methods are just as valid in
- ``list_display`` as any other model method, so it's perfectly OK to do
- this::
- list_display = ('__unicode__', 'some_other_field')
- * Usually, elements of ``list_display`` that aren't actual database fields
- can't be used in sorting (because Django does all the sorting at the
- database level).
- However, if an element of ``list_display`` represents a certain database
- field, you can indicate this fact by setting the ``admin_order_field``
- attribute of the item.
- For example::
- class Person(models.Model):
- first_name = models.CharField(max_length=50)
- color_code = models.CharField(max_length=6)
- def colored_first_name(self):
- return '<span style="color: #%s;">%s</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')
- The above will tell Django to order by the ``first_name`` field when
- trying to sort by ``colored_first_name`` in the admin.
- ``list_display_links``
- ~~~~~~~~~~~~~~~~~~~~~~
- Set ``list_display_links`` to control 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 which columns are linked. Set
- ``list_display_links`` to a list or tuple of field names (in the same format as
- ``list_display``) to link.
- ``list_display_links`` can specify one or many field names. As long as the
- field names appear in ``list_display``, Django doesn't care how many (or how
- few) fields are linked. The only requirement is: If you want to use
- ``list_display_links``, 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')
- .. _admin-list-editable:
- ``list_editable``
- ~~~~~~~~~~~~~~~~~
- .. versionadded:: 1.1
- 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:
- * To use ``list_editable`` you must have defined ``ordering`` defined on
- either your model or your ``ModelAdmin``.
- * 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 any of these rules are broken.
- ``list_filter``
- ~~~~~~~~~~~~~~~
- Set ``list_filter`` to activate filters in the right sidebar of the change list
- page of the admin. This should be a list of field names, and each specified
- field should be either a ``BooleanField``, ``CharField``, ``DateField``,
- ``DateTimeField``, ``IntegerField`` or ``ForeignKey``.
- This example, taken from the ``django.contrib.auth.models.User`` model, shows
- how both ``list_display`` and ``list_filter`` work::
- class UserAdmin(admin.ModelAdmin):
- list_display = ('username', 'email', 'first_name', 'last_name', 'is_staff')
- list_filter = ('is_staff', 'is_superuser')
- The above code results in an admin change list page that looks like this:
- .. image:: _images/users_changelist.png
- (This example also has ``search_fields`` defined. See below.)
- ``list_per_page``
- ~~~~~~~~~~~~~~~~~
- Set ``list_per_page`` to control how many items appear on each paginated admin
- change list page. By default, this is set to ``100``.
- ``list_select_related``
- ~~~~~~~~~~~~~~~~~~~~~~~
- 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 ``True`` or ``False``. Default is ``False``.
- Note that Django will use ``select_related()``, regardless of this setting,
- if one of the ``list_display`` fields is a ``ForeignKey``.
- For more on ``select_related()``, see
- :ref:`the select_related() docs <select-related>`.
- ``inlines``
- ~~~~~~~~~~~
- See ``InlineModelAdmin`` objects below.
- ``ordering``
- ~~~~~~~~~~~~
- Set ``ordering`` to specify how objects on the admin change list page should be
- ordered. 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.
- .. admonition:: Note
- Django will only honor the first element in the list/tuple; any others
- will be ignored.
- ``prepopulated_fields``
- ~~~~~~~~~~~~~~~~~~~~~~~
- Set ``prepopulated_fields`` to a dictionary mapping field names to the fields
- it should prepopulate from::
- 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.
- ``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.
- ``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 ArticleAdmin(admin.ModelAdmin):
- raw_id_fields = ("newspaper",)
- ``save_as``
- ~~~~~~~~~~~
- Set ``save_as`` to enable a "save as" feature on admin change forms.
- Normally, objects have three save options: "Save", "Save and continue editing"
- and "Save and add another". If ``save_as`` is ``True``, "Save and add another"
- will be replaced by a "Save as" button.
- "Save as" means the object will be saved as a new object (with a new ID),
- rather than the old object.
- By default, ``save_as`` is set to ``False``.
- ``save_on_top``
- ~~~~~~~~~~~~~~~
- Set ``save_on_top`` to add save buttons across the top of your admin change
- forms.
- Normally, the save buttons appear only at the bottom of the forms. If you set
- ``save_on_top``, the buttons will appear both on the top and the bottom.
- By default, ``save_on_top`` is set to ``False``.
- ``search_fields``
- ~~~~~~~~~~~~~~~~~
- 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`` with
- the lookup API "follow" notation::
- search_fields = ['foreign_key__related_fieldname']
- 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 ``john lennon``, Django will do the equivalent of this SQL
- ``WHERE`` clause::
- WHERE (first_name ILIKE '%john%' OR last_name ILIKE '%john%')
- AND (first_name ILIKE '%lennon%' OR last_name ILIKE '%lennon%')
- For faster and/or more restrictive searches, prefix the field name
- with an operator:
- ``^``
- Matches the beginning of the field. For example, if ``search_fields`` is
- set to ``['^first_name', '^last_name']`` and a user searches for
- ``john lennon``, Django will do the equivalent of this SQL ``WHERE``
- clause::
- WHERE (first_name ILIKE 'john%' OR last_name ILIKE 'john%')
- AND (first_name ILIKE 'lennon%' OR last_name ILIKE 'lennon%')
- 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 ``john lennon``, Django will do the equivalent
- of this SQL ``WHERE`` clause::
- WHERE (first_name ILIKE 'john' OR last_name ILIKE 'john')
- AND (first_name ILIKE 'lennon' OR last_name ILIKE 'lennon')
- Note that the query input is split by spaces, so, following this example,
- it's currently not possible to search for all records in which
- ``first_name`` is exactly ``'john winston'`` (containing a space).
- ``@``
- Performs a full-text match. This is like the default search method but uses
- an index. Currently this is only available for MySQL.
- ``formfield_overrides``
- ~~~~~~~~~~~~~~~~~~~~~~~
- This provides a quick-and-dirty way to override some of the
- :class:`~django.forms.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::
- 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},
- }
- 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
- :meth:`~django.forms.Field.__init__`. See :ref:`ref-forms-api` for details.
- .. warning::
- If you want to use a custom widget with a relation field (i.e.
- :class:`~django.db.models.ForeignKey` or
- :class:`~django.db.models.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.
- ``actions``
- ~~~~~~~~~~~
- A list of actions to make available on the change list page. See
- :ref:`ref-contrib-admin-actions` for details.
- ``actions_on_top``, ``actions_on_bottom``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Controls where on the page the actions bar appears. By default, the admin
- changelist displays actions at the top of the page (``actions_on_top = True;
- actions_on_bottom = False``).
- ``ModelAdmin`` methods
- ----------------------
- ``save_model(self, request, obj, form, change)``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- 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.
- For example to attach ``request.user`` to the object prior to saving::
- class ArticleAdmin(admin.ModelAdmin):
- def save_model(self, request, obj, form, change):
- obj.user = request.user
- obj.save()
- ``save_formset(self, request, form, formset, change)``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The ``save_formset`` method is given the ``HttpRequest``, the parent
- ``ModelForm`` instance and a boolean value based on whether it is adding or
- changing the parent object.
- For example to attach ``request.user`` to each changed formset
- model instance::
- class ArticleAdmin(admin.ModelAdmin):
- def save_formset(self, request, form, formset, change):
- instances = formset.save(commit=False)
- for instance in instances:
- instance.user = request.user
- instance.save()
- formset.save_m2m()
- ``get_urls(self)``
- ~~~~~~~~~~~~~~~~~~~
- .. versionadded:: 1.1
- 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 :ref:`topics-http-urls`::
- class MyModelAdmin(admin.ModelAdmin):
- def get_urls(self):
- urls = super(MyModelAdmin, self).get_urls()
- my_urls = patterns('',
- (r'^my_view/$', self.my_view)
- )
- return my_urls + urls
- .. 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.
- Note, however, that the ``self.my_view`` function registered above will *not*
- have any permission check done; it'll be accessible to the general public. Since
- this is usually not what you want, Django provides a convience wrapper to check
- permissions. This wrapper is :meth:`AdminSite.admin_view` (i.e.
- ``self.admin_site.admin_view`` inside a ``ModelAdmin`` instance); use it like
- so::
- class MyModelAdmin(admin.ModelAdmin):
- def get_urls(self):
- urls = super(MyModelAdmin, self).get_urls()
- my_urls = patterns('',
- (r'^my_view/$', self.admin_site.admin_view(self.my_view))
- )
- return my_urls + urls
- Notice the wrapped view in the fifth line above::
- (r'^my_view/$', self.admin_site.admin_view(self.my_view))
- This wrapping will protect ``self.my_view`` from unauthorized access.
- ``formfield_for_foreignkey(self, db_field, request, **kwargs)``
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- .. versionadded:: 1.1
- The ``formfield_for_foreignkey`` method on a ``ModelAdmin`` allows you to
- override the default formfield for a foreign key 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.object.filter(owner=request.user)
- return db_field.formfield(**kwargs)
- 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 the cars owned by the ``User`` instance.
- ``ModelAdmin`` media 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",)
- Keep in mind that this will be prepended with ``MEDIA_URL``. The same rules
- apply as :ref:`regular media definitions on forms <topics-forms-media>`.
- Adding custom validation to the admin
- -------------------------------------
- Adding custom validation of data in the admin is quite easy. The automatic admin
- interfaces reuses :mod:`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):
- class Meta:
- model = Article
- 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
- :ref:`forms <ref-forms-index>` documentation on :ref:`custom validation
- <ref-forms-validation>` for more information.
- .. _admin-inlines:
- ``InlineModelAdmin`` objects
- ============================
- The admin interface has the ability to edit models on the same page as a
- parent model. These are called inlines. You can add them to a model by
- specifying them in a ``ModelAdmin.inlines`` attribute::
- class BookInline(admin.TabularInline):
- model = Book
- class AuthorAdmin(admin.ModelAdmin):
- inlines = [
- BookInline,
- ]
- Django provides two subclasses of ``InlineModelAdmin`` and they are:
- * ``TabularInline``
- * ``StackedInline``
- The difference between these two is merely the template used to render them.
- ``InlineModelAdmin`` options
- -----------------------------
- The ``InlineModelAdmin`` class is a subclass of ``ModelAdmin`` so it inherits
- all the same functionality as well as some of its own:
- ``model``
- ~~~~~~~~~
- The model in which the inline is using. This is required.
- ``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.
- ``formset``
- ~~~~~~~~~~~
- This defaults to ``BaseInlineFormSet``. Using your own formset can give you
- many possibilities of customization. Inlines are built around
- :ref:`model formsets <model-formsets>`.
- ``form``
- ~~~~~~~~
- The value for ``form`` is inherited from ``ModelAdmin``. This is what is
- passed through to ``formset_factory`` when creating the formset for this
- inline.
- ``extra``
- ~~~~~~~~~
- This controls the number of extra forms the formset will display in addition
- to the initial forms. See the
- :ref:`formsets documentation <topics-forms-formsets>` for more information.
- ``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 :ref:`model-formsets-max-num` for more information.
- ``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",)
- ``template``
- ~~~~~~~~~~~~
- The template used to render the inline on the page.
- ``verbose_name``
- ~~~~~~~~~~~~~~~~
- An override to the ``verbose_name`` found in the model's inner ``Meta`` class.
- ``verbose_name_plural``
- ~~~~~~~~~~~~~~~~~~~~~~~
- An override to the ``verbose_name_plural`` found in the model's inner ``Meta``
- class.
- 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::
- 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::
- class FriendshipInline(admin.TabularInline):
- model = Friendship
- fk_name = "to_person"
- class PersonAdmin(admin.ModelAdmin):
- inlines = [
- FriendshipInline,
- ]
- Working with Many-to-Many Intermediary Models
- ----------------------------------------------
- By default, admin widgets for many-to-many relations will be displayed inline
- on whichever model contains the actual reference to the ``ManyToManyField``.
- However, 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::
- 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)
- The first step in displaying this intermediate model in the admin is to
- define an inline class for the ``Membership`` model::
- 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. Let's say
- you have the following models::
- class Image(models.Model):
- image = models.ImageField(upload_to="images")
- content_type = models.ForeignKey(ContentType)
- object_id = models.PositiveIntegerField()
- content_object = generic.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 simply use ``GenericInlineModelAdmin`` provided by
- ``django.contrib.contenttypes.generic``. In your ``admin.py`` for this
- example app::
- from django.contrib import admin
- from django.contrib.contenttypes import generic
- from myproject.myapp.models import Image, Product
- class ImageInline(generic.GenericTabularInline):
- model = Image
- class ProductAdmin(admin.ModelAdmin):
- inlines = [
- ImageInline,
- ]
- admin.site.register(Product, ProductAdmin)
- ``django.contrib.contenttypes.generic`` provides both a ``GenericTabularInline``
- and ``GenericStackedInline`` and behave just like any other inline. See the
- :ref:`contenttypes documentation <ref-contrib-contenttypes>` for more specific
- information.
- Overriding Admin Templates
- ==========================
- 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.
- Set up your projects admin template directories
- -----------------------------------------------
- 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 ``TEMPLATE_DIRS``.
- 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.
- 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`` block. Therefore here is our
- new ``change_form.html`` :
- .. code-block:: html+django
- {% extends "admin/change_form.html" %}
- {% load i18n %}
- {% block object-tools %}
- {% if change %}{% if not is_popup %}
- <ul class="object-tools">
- <li><a href="history/" class="historylink">{% trans "History" %}</a></li>
- <li><a href="mylink/" class="historylink">My Link</a></li>
- {% if has_absolute_url %}
- <li><a href="../../../r/{{ content_type_id }}/{{ object_id }}/" class="viewsitelink">
- {% trans "View on site" %}</a>
- </li>
- {% endif%}
- </ul>
- {% endif %}{% endif %}
- {% endblock %}
- And that's it! If we placed this file in the ``templates/admin/my_app``
- directory, our link would appear on every model's change form.
- Templates which may be overridden per app or model
- --------------------------------------------------
- Not every template in ``contrib\admin\templates\admin`` may be overridden per
- app or per model. The following can:
- * ``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_request.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.
- Root and login templates
- ------------------------
- If you wish to change the index or login templates, you are better off creating
- your own ``AdminSite`` instance (see below), and changing the ``index_template``
- or ``login_template`` properties.
- ``AdminSite`` objects
- =====================
- 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.
- If you'd like to set up your own administrative site with custom
- behavior, however, 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 using the default.
- Hooking ``AdminSite`` instances into your URLconf
- -------------------------------------------------
- The last step in setting up the Django admin is to hook your ``AdminSite``
- instance into your URLconf. Do this by pointing a given URL at the
- ``AdminSite.root`` method.
- In this example, we register the default ``AdminSite`` instance
- ``django.contrib.admin.site`` at the URL ``/admin/`` ::
- # urls.py
- from django.conf.urls.defaults import *
- from django.contrib import admin
- admin.autodiscover()
- urlpatterns = patterns('',
- ('^admin/', include(admin.site.urls)),
- )
- Above we used ``admin.autodiscover()`` to automatically load the
- ``INSTALLED_APPS`` admin.py modules.
- In this example, we register the ``AdminSite`` instance
- ``myproject.admin.admin_site`` at the URL ``/myadmin/`` ::
- # urls.py
- from django.conf.urls.defaults import *
- from myproject.admin import admin_site
- urlpatterns = patterns('',
- ('^myadmin/', include(admin_site.urls)),
- )
- There is really no need to use autodiscover when using your own ``AdminSite``
- instance since you will likely be importing all the per-app admin.py modules
- in your ``myproject.admin`` module.
- Multiple admin sites in the same URLconf
- ----------------------------------------
- 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.
- .. versionchanged:: 1.1
- The method for hooking ``AdminSite`` instances into urls has changed in
- Django 1.1.
- 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::
- # urls.py
- from django.conf.urls.defaults import *
- from myproject.admin import basic_site, advanced_site
- urlpatterns = patterns('',
- ('^basic-admin/', include(basic_site.urls)),
- ('^advanced-admin/', include(advanced_site.urls)),
- )
- Adding views to admin sites
- ---------------------------
- .. versionadded:: 1.1
- It possible to add additional views to the admin site in the same way one can
- add them to ``ModelAdmins``. This by using the ``get_urls()`` method on an
- AdminSite in the same way as `described above`__
- __ `get_urls(self)`_
|