Fixed #8500 -- Allowed overriding the default admin site instance.

This commit is contained in:
Raffaele Salmaso 2016-12-29 18:51:26 +01:00 committed by Tim Graham
parent d0a42a14c0
commit da3df5b878
9 changed files with 108 additions and 2 deletions

View File

@ -666,6 +666,7 @@ answer newbie questions, and generally made Django that much better:
Rachel Tobin <rmtobin@me.com>
Rachel Willmer <http://www.willmer.com/kb/>
Radek Švarz <http://www.svarz.cz/translate/>
Raffaele Salmaso <raffaele@salmaso.org>
Rajesh Dhawan <rajesh.dhawan@gmail.com>
Ramez Ashraf <ramezashraf@gmail.com>
Ramin Farajpour Cami <ramin.blackhat@gmail.com>

View File

@ -7,6 +7,7 @@ from django.utils.translation import gettext_lazy as _
class SimpleAdminConfig(AppConfig):
"""Simple AppConfig which does not do automatic discovery."""
default_site = 'django.contrib.admin.sites.AdminSite'
name = 'django.contrib.admin'
verbose_name = _("Administration")

View File

@ -9,6 +9,8 @@ from django.db.models.base import ModelBase
from django.http import Http404, HttpResponseRedirect
from django.template.response import TemplateResponse
from django.urls import NoReverseMatch, reverse
from django.utils.functional import LazyObject
from django.utils.module_loading import import_string
from django.utils.text import capfirst
from django.utils.translation import gettext as _, gettext_lazy
from django.views.decorators.cache import never_cache
@ -518,6 +520,14 @@ class AdminSite:
], context)
class DefaultAdminSite(LazyObject):
def _setup(self):
AdminSiteClass = import_string(apps.get_app_config('admin').default_site)
self._wrapped = AdminSiteClass()
# This global object represents the default admin site, for the common case.
# You can instantiate AdminSite in your own code to create a custom admin site.
site = AdminSite()
# You can provide your own AdminSite using the (Simple)AdminConfig.default_site
# attribute. You can also instantiate AdminSite in your own code to create a
# custom admin site.
site = DefaultAdminSite()

View File

@ -157,6 +157,15 @@ application and imports it.
This class works like :class:`~django.contrib.admin.apps.AdminConfig`,
except it doesn't call :func:`~django.contrib.admin.autodiscover()`.
.. attribute:: default_site
.. versionadded:: 2.1
A dotted import path to the default admin site's class or to a callable
that returns a site instance. Defaults to
``'django.contrib.admin.sites.AdminSite'``. See
:ref:`overriding-default-admin-site` for usage.
.. function:: autodiscover
This function attempts to import an ``admin`` module in each installed
@ -2627,6 +2636,9 @@ creating your own ``AdminSite`` instance (see below), and changing the
this class is created as ``django.contrib.admin.site`` and you can
register your models and ``ModelAdmin`` instances with it.
If you want to customize the default admin site, you can :ref:`override it
<overriding-default-admin-site>`.
When constructing an instance of an ``AdminSite``, you can provide
a unique instance name using the ``name`` argument to the constructor. This
instance name is used to identify the instance, especially when
@ -2819,6 +2831,43 @@ own ``AdminSite`` instance since you will likely be importing all the per-app
put ``'django.contrib.admin.apps.SimpleAdminConfig'`` instead of
``'django.contrib.admin'`` in your :setting:`INSTALLED_APPS` setting.
.. _overriding-default-admin-site:
Overriding the default admin site
---------------------------------
.. versionadded:: 2.1
You can override the default ``django.contrib.admin.site`` by setting the
:attr:`~.SimpleAdminConfig.default_site` attribute of a custom ``AppConfig``
to the dotted import path of either a ``AdminSite`` subclass or a callable that
returns a site instance.
.. snippet::
:filename: myproject/admin.py
from django.contrib import admin
class MyAdminSite(admin.AdminSite):
...
.. snippet::
:filename: myproject/apps.py
from django.contrib.admin.apps import AdminConfig
class MyAdminConfig(AdminConfig):
default_site = 'myproject.admin.MyAdminSite'
.. snippet::
:filename: myproject/settings.py
INSTALLED_APPS = [
...
'myproject.apps.MyAdminConfig', # replaces 'django.contrib.admin'
...
]
.. _multiple-admin-sites:
Multiple admin sites in the same URLconf

View File

@ -40,6 +40,9 @@ Minor features
* The new :meth:`.ModelAdmin.delete_queryset` method allows customizing the
deletion process of the "delete selected objects" action.
* You can now :ref:`override the the default admin site
<overriding-default-admin-site>`.
:mod:`django.contrib.admindocs`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

View File

@ -0,0 +1,6 @@
from django.contrib.admin.apps import SimpleAdminConfig
class MyCustomAdminConfig(SimpleAdminConfig):
verbose_name = 'My custom default admin site.'
default_site = 'admin_default_site.sites.CustomAdminSite'

View File

@ -0,0 +1,5 @@
from django.contrib import admin
class CustomAdminSite(admin.AdminSite):
pass

View File

@ -0,0 +1,31 @@
from django.contrib import admin
from django.contrib.admin import sites
from django.test import SimpleTestCase, override_settings
@override_settings(INSTALLED_APPS=[
'admin_default_site.apps.MyCustomAdminConfig',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
])
class CustomAdminSiteTests(SimpleTestCase):
def setUp(self):
# Reset admin.site since it may have already been instantiated by
# another test app.
self._old_site = admin.site
admin.site = sites.site = sites.DefaultAdminSite()
def tearDown(self):
admin.site = sites.site = self._old_site
def test_use_custom_admin_site(self):
self.assertEqual(admin.site.__class__.__name__, 'CustomAdminSite')
class DefaultAdminSiteTests(SimpleTestCase):
def test_use_default_admin_site(self):
self.assertEqual(admin.site.__class__.__name__, 'AdminSite')