summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--django/contrib/admin/checks.py28
-rw-r--r--tests/admin_checks/tests.py51
2 files changed, 73 insertions, 6 deletions
diff --git a/django/contrib/admin/checks.py b/django/contrib/admin/checks.py
index a5bcc3f6df..76c3bd5657 100644
--- a/django/contrib/admin/checks.py
+++ b/django/contrib/admin/checks.py
@@ -15,6 +15,7 @@ from django.forms.models import (
)
from django.template import engines
from django.template.backends.django import DjangoTemplates
+from django.utils.module_loading import import_string
def _issubclass(cls, classinfo):
@@ -28,6 +29,23 @@ def _issubclass(cls, classinfo):
return False
+def _contains_subclass(class_path, candidate_paths):
+ """
+ Return whether or not a dotted class path (or a subclass of that class) is
+ found in a list of candidate paths.
+ """
+ cls = import_string(class_path)
+ for path in candidate_paths:
+ try:
+ candidate_cls = import_string(path)
+ except ImportError:
+ # ImportErrors are raised elsewhere.
+ continue
+ if _issubclass(candidate_cls, cls):
+ return True
+ return False
+
+
def check_admin_app(app_configs, **kwargs):
from django.contrib.admin.sites import all_sites
errors = []
@@ -72,8 +90,7 @@ def check_dependencies(**kwargs):
else:
if ('django.contrib.auth.context_processors.auth'
not in django_templates_instance.context_processors and
- 'django.contrib.auth.backends.ModelBackend'
- in settings.AUTHENTICATION_BACKENDS):
+ _contains_subclass('django.contrib.auth.backends.ModelBackend', settings.AUTHENTICATION_BACKENDS)):
errors.append(checks.Error(
"'django.contrib.auth.context_processors.auth' must be "
"enabled in DjangoTemplates (TEMPLATES) if using the default "
@@ -88,15 +105,14 @@ def check_dependencies(**kwargs):
"the admin application.",
id='admin.E404',
))
- if ('django.contrib.auth.middleware.AuthenticationMiddleware'
- not in settings.MIDDLEWARE):
+
+ if not _contains_subclass('django.contrib.auth.middleware.AuthenticationMiddleware', settings.MIDDLEWARE):
errors.append(checks.Error(
"'django.contrib.auth.middleware.AuthenticationMiddleware' must "
"be in MIDDLEWARE in order to use the admin application.",
id='admin.E408',
))
- if ('django.contrib.messages.middleware.MessageMiddleware'
- not in settings.MIDDLEWARE):
+ if not _contains_subclass('django.contrib.messages.middleware.MessageMiddleware', settings.MIDDLEWARE):
errors.append(checks.Error(
"'django.contrib.messages.middleware.MessageMiddleware' must "
"be in MIDDLEWARE in order to use the admin application.",
diff --git a/tests/admin_checks/tests.py b/tests/admin_checks/tests.py
index df1cd6f96f..c7fe39b91e 100644
--- a/tests/admin_checks/tests.py
+++ b/tests/admin_checks/tests.py
@@ -1,7 +1,10 @@
from django import forms
from django.contrib import admin
from django.contrib.admin import AdminSite
+from django.contrib.auth.backends import ModelBackend
+from django.contrib.auth.middleware import AuthenticationMiddleware
from django.contrib.contenttypes.admin import GenericStackedInline
+from django.contrib.messages.middleware import MessageMiddleware
from django.core import checks
from django.test import SimpleTestCase, override_settings
@@ -37,6 +40,18 @@ class MyAdmin(admin.ModelAdmin):
return ['error!']
+class AuthenticationMiddlewareSubclass(AuthenticationMiddleware):
+ pass
+
+
+class MessageMiddlewareSubclass(MessageMiddleware):
+ pass
+
+
+class ModelBackendSubclass(ModelBackend):
+ pass
+
+
@override_settings(
SILENCED_SYSTEM_CHECKS=['fields.W342'], # ForeignKey(unique=True)
INSTALLED_APPS=[
@@ -130,6 +145,27 @@ class SystemChecksTestCase(SimpleTestCase):
self.assertEqual(admin.checks.check_dependencies(), expected[1:])
@override_settings(
+ AUTHENTICATION_BACKENDS=['admin_checks.tests.ModelBackendSubclass'],
+ TEMPLATES=[{
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': ['django.contrib.messages.context_processors.messages'],
+ },
+ }],
+ )
+ def test_context_processor_dependencies_model_backend_subclass(self):
+ self.assertEqual(admin.checks.check_dependencies(), [
+ checks.Error(
+ "'django.contrib.auth.context_processors.auth' must be "
+ "enabled in DjangoTemplates (TEMPLATES) if using the default "
+ "auth backend in order to use the admin application.",
+ id='admin.E402',
+ ),
+ ])
+
+ @override_settings(
TEMPLATES=[
{
'BACKEND': 'django.template.backends.dummy.TemplateStrings',
@@ -169,6 +205,21 @@ class SystemChecksTestCase(SimpleTestCase):
]
self.assertEqual(errors, expected)
+ @override_settings(MIDDLEWARE=[
+ 'admin_checks.tests.AuthenticationMiddlewareSubclass',
+ 'admin_checks.tests.MessageMiddlewareSubclass',
+ ])
+ def test_middleware_subclasses(self):
+ self.assertEqual(admin.checks.check_dependencies(), [])
+
+ @override_settings(MIDDLEWARE=[
+ 'django.contrib.does.not.Exist',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ ])
+ def test_admin_check_ignores_import_error_in_middleware(self):
+ self.assertEqual(admin.checks.check_dependencies(), [])
+
def test_custom_adminsite(self):
class CustomAdminSite(admin.AdminSite):
pass