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 Tobin <rmtobin@me.com>
Rachel Willmer <http://www.willmer.com/kb/> Rachel Willmer <http://www.willmer.com/kb/>
Radek Švarz <http://www.svarz.cz/translate/> Radek Švarz <http://www.svarz.cz/translate/>
Raffaele Salmaso <raffaele@salmaso.org>
Rajesh Dhawan <rajesh.dhawan@gmail.com> Rajesh Dhawan <rajesh.dhawan@gmail.com>
Ramez Ashraf <ramezashraf@gmail.com> Ramez Ashraf <ramezashraf@gmail.com>
Ramin Farajpour Cami <ramin.blackhat@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): class SimpleAdminConfig(AppConfig):
"""Simple AppConfig which does not do automatic discovery.""" """Simple AppConfig which does not do automatic discovery."""
default_site = 'django.contrib.admin.sites.AdminSite'
name = 'django.contrib.admin' name = 'django.contrib.admin'
verbose_name = _("Administration") verbose_name = _("Administration")

View File

@ -9,6 +9,8 @@ from django.db.models.base import ModelBase
from django.http import Http404, HttpResponseRedirect from django.http import Http404, HttpResponseRedirect
from django.template.response import TemplateResponse from django.template.response import TemplateResponse
from django.urls import NoReverseMatch, reverse 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.text import capfirst
from django.utils.translation import gettext as _, gettext_lazy from django.utils.translation import gettext as _, gettext_lazy
from django.views.decorators.cache import never_cache from django.views.decorators.cache import never_cache
@ -518,6 +520,14 @@ class AdminSite:
], context) ], 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. # 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. # You can provide your own AdminSite using the (Simple)AdminConfig.default_site
site = AdminSite() # 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`, This class works like :class:`~django.contrib.admin.apps.AdminConfig`,
except it doesn't call :func:`~django.contrib.admin.autodiscover()`. 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 .. function:: autodiscover
This function attempts to import an ``admin`` module in each installed 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 this class is created as ``django.contrib.admin.site`` and you can
register your models and ``ModelAdmin`` instances with it. 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 When constructing an instance of an ``AdminSite``, you can provide
a unique instance name using the ``name`` argument to the constructor. This a unique instance name using the ``name`` argument to the constructor. This
instance name is used to identify the instance, especially when 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 put ``'django.contrib.admin.apps.SimpleAdminConfig'`` instead of
``'django.contrib.admin'`` in your :setting:`INSTALLED_APPS` setting. ``'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:
Multiple admin sites in the same URLconf 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 * The new :meth:`.ModelAdmin.delete_queryset` method allows customizing the
deletion process of the "delete selected objects" action. 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` :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')