mirror of
				https://github.com/django/django.git
				synced 2025-11-03 21:25:09 +00:00 
			
		
		
		
	SmileyChris. git-svn-id: http://code.djangoproject.com/svn/django/trunk@9432 bcc190cf-cafb-0310-a4f2-bffc1f526a37
		
			
				
	
	
		
			1073 lines
		
	
	
	
		
			38 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			1073 lines
		
	
	
	
		
			38 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
.. _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.
 | 
						|
 | 
						|
``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')
 | 
						|
 | 
						|
Finally, note that in order to use ``list_display_links``, you must define
 | 
						|
``list_display``, too.
 | 
						|
 | 
						|
``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.
 | 
						|
 | 
						|
``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()
 | 
						|
 | 
						|
``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/(.*)', admin.site.root),
 | 
						|
    )
 | 
						|
 | 
						|
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/(.*)', admin_site.root),
 | 
						|
    )
 | 
						|
 | 
						|
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.
 | 
						|
 | 
						|
Note that the regular expression in the URLpattern *must* group everything in
 | 
						|
the URL that comes after the URL root -- hence the ``(.*)`` in these examples.
 | 
						|
 | 
						|
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.
 | 
						|
 | 
						|
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/(.*)', basic_site.root),
 | 
						|
        ('^advanced-admin/(.*)', advanced_site.root),
 | 
						|
    )
 |