Commit 0490d72f authored by Vincenzo Pandolfo's avatar Vincenzo Pandolfo Committed by Tim Graham
Browse files

Fixed #24116 -- Moved AdminSite.check_dependencies() to system checks.

parent 956cde80
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
from django.apps import AppConfig
from django.contrib.admin.checks import check_admin_app
from django.contrib.admin.checks import check_admin_app, check_dependencies
from django.core import checks
from django.utils.translation import ugettext_lazy as _

@@ -11,6 +11,7 @@ class SimpleAdminConfig(AppConfig):
    verbose_name = _("Administration")

    def ready(self):
        checks.register(check_dependencies, checks.Tags.admin)
        checks.register(check_admin_app, checks.Tags.admin)


+43 −0
Original line number Diff line number Diff line
@@ -3,6 +3,8 @@ from __future__ import unicode_literals

from itertools import chain

from django.apps import apps
from django.conf import settings
from django.contrib.admin.utils import (
    NotRelationField, flatten, get_fields_from_path,
)
@@ -12,6 +14,7 @@ from django.db import models
from django.forms.models import (
    BaseModelForm, BaseModelFormSet, _get_foreign_key,
)
from django.template.engine import Engine


def check_admin_app(**kwargs):
@@ -20,6 +23,46 @@ def check_admin_app(**kwargs):
    return system_check_errors


def check_dependencies(**kwargs):
    """
    Check that the admin's dependencies are correctly installed.
    """
    errors = []
    # contrib.contenttypes must be installed.
    if not apps.is_installed('django.contrib.contenttypes'):
        missing_app = checks.Error(
            "'django.contrib.contenttypes' must be in INSTALLED_APPS in order "
            "to use the admin application.",
            id="admin.E401",
        )
        errors.append(missing_app)
    # The auth context processor must be installed if using the default
    # authentication backend.
    try:
        default_template_engine = Engine.get_default()
    except Exception:
        # Skip this non-critical check:
        # 1. if the user has a non-trivial TEMPLATES setting and Django
        #    can't find a default template engine
        # 2. if anything goes wrong while loading template engines, in
        #    order to avoid raising an exception from a confusing location
        # Catching ImproperlyConfigured suffices for 1. but 2. requires
        # catching all exceptions.
        pass
    else:
        if ('django.contrib.auth.context_processors.auth'
                not in default_template_engine.context_processors
                and 'django.contrib.auth.backends.ModelBackend'
                in settings.AUTHENTICATION_BACKENDS):
            missing_template = checks.Error(
                "'django.contrib.auth.context_processors.auth' must be in "
                "TEMPLATES in order to use the admin application.",
                id="admin.E402"
                )
            errors.append(missing_template)
    return errors


class BaseModelAdminChecks(object):

    def check(self, admin_obj, **kwargs):
+0 −38
Original line number Diff line number Diff line
@@ -7,7 +7,6 @@ from django.contrib.auth import REDIRECT_FIELD_NAME
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.db.models.base import ModelBase
from django.http import Http404, HttpResponseRedirect
from django.template.engine import Engine
from django.template.response import TemplateResponse
from django.urls import NoReverseMatch, reverse
from django.utils import six
@@ -172,40 +171,6 @@ class AdminSite(object):
        """
        return request.user.is_active and request.user.is_staff

    def check_dependencies(self):
        """
        Check that all things needed to run the admin have been correctly installed.

        The default implementation checks that admin and contenttypes apps are
        installed, as well as the auth context processor.
        """
        if not apps.is_installed('django.contrib.admin'):
            raise ImproperlyConfigured(
                "Put 'django.contrib.admin' in your INSTALLED_APPS "
                "setting in order to use the admin application.")
        if not apps.is_installed('django.contrib.contenttypes'):
            raise ImproperlyConfigured(
                "Put 'django.contrib.contenttypes' in your INSTALLED_APPS "
                "setting in order to use the admin application.")
        try:
            default_template_engine = Engine.get_default()
        except Exception:
            # Skip this non-critical check:
            # 1. if the user has a non-trivial TEMPLATES setting and Django
            #    can't find a default template engine
            # 2. if anything goes wrong while loading template engines, in
            #    order to avoid raising an exception from a confusing location
            # Catching ImproperlyConfigured suffices for 1. but 2. requires
            # catching all exceptions.
            pass
        else:
            if ('django.contrib.auth.context_processors.auth'
                    not in default_template_engine.context_processors):
                raise ImproperlyConfigured(
                    "Enable 'django.contrib.auth.context_processors.auth' "
                    "in your TEMPLATES setting in order to use the admin "
                    "application.")

    def admin_view(self, view, cacheable=False):
        """
        Decorator to create an admin view attached to this ``AdminSite``. This
@@ -257,9 +222,6 @@ class AdminSite(object):
        # and django.contrib.contenttypes.views imports ContentType.
        from django.contrib.contenttypes import views as contenttype_views

        if settings.DEBUG:
            self.check_dependencies()

        def wrap(view, cacheable=False):
            def wrapper(*args, **kwargs):
                return self.admin_view(view, cacheable)(*args, **kwargs)
+10 −0
Original line number Diff line number Diff line
@@ -409,6 +409,16 @@ registered as an inline on a :class:`~django.contrib.admin.ModelAdmin`.
* **admin.E304**: ``<model>`` has no ``GenericForeignKey`` using content type
  field ``<field name>`` and object ID field ``<field name>``.

AdminSite
~~~~~~~~~

The following checks are performed on the default
:class:`~django.contrib.admin.AdminSite`:

* **admin.E401**: :mod:`django.contrib.contenttypes` must be in
  :setting:`INSTALLED_APPS` in order to use the admin application.
* **admin.E402**: :mod:`django.contrib.auth.context_processors.auth`
  must be in :setting:`TEMPLATES` in order to use the admin application.

Auth
----
+38 −0
Original line number Diff line number Diff line
@@ -54,6 +54,44 @@ class SystemChecksTestCase(SimpleTestCase):
            admin.site.unregister(Song)
            admin.sites.system_check_errors = []

    @override_settings(INSTALLED_APPS=['django.contrib.admin'])
    def test_contenttypes_dependency(self):
        errors = admin.checks.check_dependencies()
        expected = [
            checks.Error(
                "'django.contrib.contenttypes' must be in "
                "INSTALLED_APPS in order to use the admin application.",
                id="admin.E401",
            )
        ]
        self.assertEqual(errors, expected)

    @override_settings(
        INSTALLED_APPS=[
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
        ],
        TEMPLATES=[{
            'BACKEND': 'django.template.backends.django.DjangoTemplates',
            'DIRS': [],
            'APP_DIRS': True,
            'OPTIONS': {
                'context_processors': [],
            },
        }],
    )
    def test_auth_contextprocessor_dependency(self):
        errors = admin.checks.check_dependencies()
        expected = [
            checks.Error(
                "'django.contrib.auth.context_processors.auth' must be in "
                "TEMPLATES in order to use the admin application.",
                id="admin.E402",
            )
        ]
        self.assertEqual(errors, expected)

    @override_settings(DEBUG=True)
    def test_custom_adminsite(self):
        class CustomAdminSite(admin.AdminSite):