mirror of https://github.com/django/django.git
[2.2.x] Fixed #30237 -- Made Authentication/SessionMiddleware and ModelBackend admin checks allow subclasses.
Backport of f976ab1b11
from master.
This commit is contained in:
parent
b150d99460
commit
d8704a4d4f
|
@ -18,6 +18,7 @@ from django.template import engines
|
||||||
from django.template.backends.django import DjangoTemplates
|
from django.template.backends.django import DjangoTemplates
|
||||||
from django.utils.deprecation import RemovedInDjango30Warning
|
from django.utils.deprecation import RemovedInDjango30Warning
|
||||||
from django.utils.inspect import get_func_args
|
from django.utils.inspect import get_func_args
|
||||||
|
from django.utils.module_loading import import_string
|
||||||
|
|
||||||
|
|
||||||
def _issubclass(cls, classinfo):
|
def _issubclass(cls, classinfo):
|
||||||
|
@ -31,6 +32,23 @@ def _issubclass(cls, classinfo):
|
||||||
return False
|
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):
|
def check_admin_app(app_configs, **kwargs):
|
||||||
from django.contrib.admin.sites import all_sites
|
from django.contrib.admin.sites import all_sites
|
||||||
errors = []
|
errors = []
|
||||||
|
@ -75,8 +93,7 @@ def check_dependencies(**kwargs):
|
||||||
else:
|
else:
|
||||||
if ('django.contrib.auth.context_processors.auth'
|
if ('django.contrib.auth.context_processors.auth'
|
||||||
not in django_templates_instance.context_processors and
|
not in django_templates_instance.context_processors and
|
||||||
'django.contrib.auth.backends.ModelBackend'
|
_contains_subclass('django.contrib.auth.backends.ModelBackend', settings.AUTHENTICATION_BACKENDS)):
|
||||||
in settings.AUTHENTICATION_BACKENDS):
|
|
||||||
errors.append(checks.Error(
|
errors.append(checks.Error(
|
||||||
"'django.contrib.auth.context_processors.auth' must be "
|
"'django.contrib.auth.context_processors.auth' must be "
|
||||||
"enabled in DjangoTemplates (TEMPLATES) if using the default "
|
"enabled in DjangoTemplates (TEMPLATES) if using the default "
|
||||||
|
@ -91,15 +108,14 @@ def check_dependencies(**kwargs):
|
||||||
"the admin application.",
|
"the admin application.",
|
||||||
id='admin.E404',
|
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(
|
errors.append(checks.Error(
|
||||||
"'django.contrib.auth.middleware.AuthenticationMiddleware' must "
|
"'django.contrib.auth.middleware.AuthenticationMiddleware' must "
|
||||||
"be in MIDDLEWARE in order to use the admin application.",
|
"be in MIDDLEWARE in order to use the admin application.",
|
||||||
id='admin.E408',
|
id='admin.E408',
|
||||||
))
|
))
|
||||||
if ('django.contrib.messages.middleware.MessageMiddleware'
|
if not _contains_subclass('django.contrib.messages.middleware.MessageMiddleware', settings.MIDDLEWARE):
|
||||||
not in settings.MIDDLEWARE):
|
|
||||||
errors.append(checks.Error(
|
errors.append(checks.Error(
|
||||||
"'django.contrib.messages.middleware.MessageMiddleware' must "
|
"'django.contrib.messages.middleware.MessageMiddleware' must "
|
||||||
"be in MIDDLEWARE in order to use the admin application.",
|
"be in MIDDLEWARE in order to use the admin application.",
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.admin import AdminSite
|
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.contenttypes.admin import GenericStackedInline
|
||||||
|
from django.contrib.messages.middleware import MessageMiddleware
|
||||||
from django.core import checks
|
from django.core import checks
|
||||||
from django.test import SimpleTestCase, override_settings
|
from django.test import SimpleTestCase, override_settings
|
||||||
|
|
||||||
|
@ -37,6 +40,18 @@ class MyAdmin(admin.ModelAdmin):
|
||||||
return ['error!']
|
return ['error!']
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticationMiddlewareSubclass(AuthenticationMiddleware):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class MessageMiddlewareSubclass(MessageMiddleware):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class ModelBackendSubclass(ModelBackend):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
@override_settings(
|
@override_settings(
|
||||||
SILENCED_SYSTEM_CHECKS=['fields.W342'], # ForeignKey(unique=True)
|
SILENCED_SYSTEM_CHECKS=['fields.W342'], # ForeignKey(unique=True)
|
||||||
INSTALLED_APPS=[
|
INSTALLED_APPS=[
|
||||||
|
@ -129,6 +144,27 @@ class SystemChecksTestCase(SimpleTestCase):
|
||||||
with self.settings(AUTHENTICATION_BACKENDS=[]):
|
with self.settings(AUTHENTICATION_BACKENDS=[]):
|
||||||
self.assertEqual(admin.checks.check_dependencies(), expected[1:])
|
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(
|
@override_settings(
|
||||||
TEMPLATES=[
|
TEMPLATES=[
|
||||||
{
|
{
|
||||||
|
@ -169,6 +205,21 @@ class SystemChecksTestCase(SimpleTestCase):
|
||||||
]
|
]
|
||||||
self.assertEqual(errors, expected)
|
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):
|
def test_custom_adminsite(self):
|
||||||
class CustomAdminSite(admin.AdminSite):
|
class CustomAdminSite(admin.AdminSite):
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in New Issue