1
0
mirror of https://github.com/django/django.git synced 2025-10-24 14:16:09 +00:00

Fixed #21829 -- Added default AppConfigs.

Thanks Russell for the report, Marc for the initial patch, Carl for the
final review, and everyone who contributed to the design discussion.
This commit is contained in:
Aymeric Augustin
2014-01-24 22:43:00 +01:00
parent 29ddae7436
commit 2ff93e027c
36 changed files with 194 additions and 111 deletions

View File

@@ -61,13 +61,12 @@ class AppConfig(object):
Factory that creates an app config from an entry in INSTALLED_APPS.
"""
try:
# If import_module succeeds, entry is a path to an app module.
# If import_module succeeds, entry is a path to an app module,
# which may specify an app config class with default_app_config.
# Otherwise, entry is a path to an app config class or an error.
module = import_module(entry)
except ImportError:
# Avoid django.utils.module_loading.import_by_path because it
# masks errors -- it reraises ImportError as ImproperlyConfigured.
mod_path, _, cls_name = entry.rpartition('.')
# Raise the original exception when entry cannot be a path to an
@@ -75,39 +74,51 @@ class AppConfig(object):
if not mod_path:
raise
mod = import_module(mod_path)
try:
cls = getattr(mod, cls_name)
except AttributeError:
# Emulate the error that "from <mod_path> import <cls_name>"
# would raise when <mod_path> exists but not <cls_name>, with
# more context (Python just says "cannot import name ...").
raise ImportError(
"cannot import name '%s' from '%s'" % (cls_name, mod_path))
# Check for obvious errors. (This check prevents duck typing, but
# it could be removed if it became a problem in practice.)
if not issubclass(cls, AppConfig):
raise ImproperlyConfigured(
"'%s' isn't a subclass of AppConfig." % entry)
# Obtain app name here rather than in AppClass.__init__ to keep
# all error checking for entries in INSTALLED_APPS in one place.
try:
app_name = cls.name
except AttributeError:
raise ImproperlyConfigured(
"'%s' must supply a name attribute." % entry)
# Ensure app_name points to a valid module.
app_module = import_module(app_name)
# Entry is a path to an app config class.
return cls(app_name, app_module)
else:
# Entry is a path to an app module.
return cls(entry, module)
try:
# If this works, the app module specifies an app config class.
entry = module.default_app_config
except AttributeError:
# Otherwise, it simply uses the default app config class.
return cls(entry, module)
else:
mod_path, _, cls_name = entry.rpartition('.')
# If we're reaching this point, we must load the app config class
# located at <mod_path>.<cls_name>.
# Avoid django.utils.module_loading.import_by_path because it
# masks errors -- it reraises ImportError as ImproperlyConfigured.
mod = import_module(mod_path)
try:
cls = getattr(mod, cls_name)
except AttributeError:
# Emulate the error that "from <mod_path> import <cls_name>"
# would raise when <mod_path> exists but not <cls_name>, with
# more context (Python just says "cannot import name ...").
raise ImportError(
"cannot import name '%s' from '%s'" % (cls_name, mod_path))
# Check for obvious errors. (This check prevents duck typing, but
# it could be removed if it became a problem in practice.)
if not issubclass(cls, AppConfig):
raise ImproperlyConfigured(
"'%s' isn't a subclass of AppConfig." % entry)
# Obtain app name here rather than in AppClass.__init__ to keep
# all error checking for entries in INSTALLED_APPS in one place.
try:
app_name = cls.name
except AttributeError:
raise ImproperlyConfigured(
"'%s' must supply a name attribute." % entry)
# Ensure app_name points to a valid module.
app_module = import_module(app_name)
# Entry is a path to an app config class.
return cls(app_name, app_module)
def get_model(self, model_name):
"""

View File

@@ -30,7 +30,7 @@ ALLOWED_HOSTS = []
# Application definition
INSTALLED_APPS = (
'django.contrib.admin.apps.AdminConfig',
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',

View File

@@ -1,6 +1,5 @@
# ACTION_CHECKBOX_NAME is unused, but should stay since its import from here
# has been referenced in documentation.
from django.contrib.admin.checks import check_admin_app
from django.contrib.admin.decorators import register
from django.contrib.admin.helpers import ACTION_CHECKBOX_NAME
from django.contrib.admin.options import ModelAdmin, HORIZONTAL, VERTICAL
@@ -9,7 +8,6 @@ from django.contrib.admin.filters import (ListFilter, SimpleListFilter,
FieldListFilter, BooleanFieldListFilter, RelatedFieldListFilter,
ChoicesFieldListFilter, DateFieldListFilter, AllValuesFieldListFilter)
from django.contrib.admin.sites import AdminSite, site
from django.core import checks
from django.utils.module_loading import autodiscover_modules
__all__ = [
@@ -24,4 +22,5 @@ __all__ = [
def autodiscover():
autodiscover_modules('admin', register_to=site)
checks.register('admin')(check_admin_app)
default_app_config = 'django.contrib.admin.apps.AdminConfig'

View File

@@ -1,11 +1,22 @@
from django.apps import AppConfig
from django.core import checks
from django.contrib.admin.checks import check_admin_app
from django.utils.translation import ugettext_lazy as _
class AdminConfig(AppConfig):
class SimpleAdminConfig(AppConfig):
"""Simple AppConfig which does not do automatic discovery."""
name = 'django.contrib.admin'
verbose_name = _("administration")
def ready(self):
checks.register('admin')(check_admin_app)
class AdminConfig(SimpleAdminConfig):
"""The default AppConfig for admin which does autodiscovery."""
def ready(self):
super(AdminConfig, self).ready()
self.module.autodiscover()

View File

@@ -161,7 +161,7 @@ class AdminSite(object):
installed, as well as the auth context processor.
"""
if not apps.is_installed('django.contrib.admin'):
raise ImproperlyConfigured("Put 'django.contrib.admin.apps.AdminConfig' in "
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 "

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.admindocs.apps.AdminDocsConfig'

View File

@@ -2,8 +2,6 @@ import inspect
import re
from django.conf import settings
from django.contrib.auth.checks import check_user_model
from django.core import checks
from django.core.exceptions import ImproperlyConfigured, PermissionDenied
from django.utils.module_loading import import_by_path
from django.middleware.csrf import rotate_token
@@ -15,10 +13,6 @@ BACKEND_SESSION_KEY = '_auth_user_backend'
REDIRECT_FIELD_NAME = 'next'
# Register the user model checks
checks.register('models')(check_user_model)
def load_backend(path):
return import_by_path(path)()
@@ -164,3 +158,6 @@ def get_permission_codename(action, opts):
Returns the codename of the permission for the specified action.
"""
return '%s_%s' % (action, opts.model_name)
default_app_config = 'django.contrib.auth.apps.AuthConfig'

View File

@@ -1,4 +1,6 @@
from django.apps import AppConfig
from django.core import checks
from django.contrib.auth.checks import check_user_model
from django.utils.translation import ugettext_lazy as _
@@ -6,3 +8,6 @@ from django.utils.translation import ugettext_lazy as _
class AuthConfig(AppConfig):
name = 'django.contrib.auth'
verbose_name = _("authentication and authorization")
def ready(self):
checks.register('models')(check_user_model)

View File

@@ -1,6 +1,6 @@
from importlib import import_module
import warnings
from django.apps import apps
from django.apps import apps as django_apps
from django.conf import settings
from django.core import urlresolvers
from django.core.exceptions import ImproperlyConfigured
@@ -16,7 +16,7 @@ def get_comment_app():
Get the comment app (i.e. "django.contrib.comments") as defined in the settings
"""
try:
app_config = apps.get_app_config(get_comment_app_name().rpartition(".")[2])
app_config = django_apps.get_app_config(get_comment_app_name().rpartition(".")[2])
except LookupError:
raise ImproperlyConfigured("The COMMENTS_APP (%r) "
"must be in INSTALLED_APPS" % settings.COMMENTS_APP)
@@ -85,3 +85,6 @@ def get_approve_url(comment):
else:
return urlresolvers.reverse("django.contrib.comments.views.moderation.approve",
args=(comment.id,))
default_app_config = 'django.contrib.comments.apps.CommentsConfig'

View File

@@ -1,8 +1 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.contrib.contenttypes.checks import check_generic_foreign_keys
from django.core import checks
checks.register('models')(check_generic_foreign_keys)
default_app_config = 'django.contrib.contenttypes.apps.ContentTypesConfig'

View File

@@ -1,8 +1,12 @@
from django.apps import AppConfig
from django.contrib.contenttypes.checks import check_generic_foreign_keys
from django.core import checks
from django.utils.translation import ugettext_lazy as _
class ContentTypesConfig(AppConfig):
name = 'django.contrib.contenttypes'
verbose_name = _("content types")
def ready(self):
checks.register('models')(check_generic_foreign_keys)

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.flatpages.apps.FlatPagesConfig'

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.formtools.apps.FormToolsConfig'

View File

@@ -4,3 +4,6 @@ if six.PY3:
memoryview = memoryview
else:
memoryview = buffer
default_app_config = 'django.contrib.gis.apps.GISConfig'

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.humanize.apps.HumanizeConfig'

View File

@@ -1,2 +1,5 @@
from django.contrib.messages.api import * # NOQA
from django.contrib.messages.constants import * # NOQA
default_app_config = 'django.contrib.messages.apps.MessagesConfig'

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.redirects.apps.RedirectsConfig'

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.sessions.apps.SessionsConfig'

View File

@@ -133,3 +133,6 @@ class GenericSitemap(Sitemap):
if self.date_field is not None:
return getattr(item, self.date_field)
return None
default_app_config = 'django.contrib.sitemaps.apps.SiteMapsConfig'

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.sites.apps.SitesConfig'

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.staticfiles.apps.StaticFilesConfig'

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.syndication.apps.SyndicationConfig'

View File

@@ -0,0 +1 @@
default_app_config = 'django.contrib.webdesign.apps.WebDesignConfig'

View File

@@ -29,7 +29,8 @@ class CheckRegistry(object):
def inner(check):
check.tags = tags
self.registered_checks.append(check)
if check not in self.registered_checks:
self.registered_checks.append(check)
return check
return inner