Commit 3326a412 authored by Aymeric Augustin's avatar Aymeric Augustin
Browse files

Deprecated importing a model before loading its application.

Refs #21719, #21680.
parent 81bb8d12
Loading
Loading
Loading
Loading
+9 −1
Original line number Diff line number Diff line
@@ -3,7 +3,7 @@ from __future__ import unicode_literals
import copy
import sys
from functools import update_wrapper
from django.utils.six.moves import zip
import warnings

from django.apps import apps
from django.apps.base import MODELS_MODULE_NAME
@@ -25,6 +25,7 @@ from django.utils.translation import ugettext_lazy as _
from django.utils.functional import curry
from django.utils.encoding import force_str, force_text
from django.utils import six
from django.utils.six.moves import zip
from django.utils.text import get_text_list, capfirst


@@ -103,6 +104,13 @@ class ModelBase(type):
                # For 'django.contrib.sites.models', this would be 'sites'.
                # For 'geo.models.places' this would be 'geo'.

                warnings.warn(
                    "Model class %s.%s doesn't declare an explicit app_label "
                    "and either isn't in an application in  INSTALLED_APPS "
                    "or else was imported before its application was loaded. "
                    "This will no longer be supported in Django 1.9."
                    % (module, name), PendingDeprecationWarning, stacklevel=2)

                model_module = sys.modules[new_class.__module__]
                package_components = model_module.__name__.split('.')
                package_components.reverse()  # find the last occurrence of 'models'
+6 −0
Original line number Diff line number Diff line
@@ -170,6 +170,12 @@ these changes.
* ``allow_syncdb`` on database routers will no longer automatically become
  ``allow_migrate``.

* All models will need to be defined inside an installed application or
  declare an explicit :attr:`~django.db.models.Options.app_label`.
  Furthermore, it won't be possible to import them before their application
  is loaded. In particular, it won't be possible to import models inside
  the root package of their application.

* If models are organized in a package, Django will no longer look for
  :ref:`initial SQL data<initial-sql>` in ``myapp/models/sql/``. Move your
  custom SQL files to ``myapp/sql/``.
+7 −0
Original line number Diff line number Diff line
@@ -181,6 +181,13 @@ Methods
    as registering signals. It is called as soon as the registry is fully
    populated.

    You cannot import models in modules that define application configuration
    classes, but you can use :meth:`get_model` to access a model class by
    name, like this::

        def ready(self):
            MyModel = self.get_model('MyModel')

Application registry
====================

+12 −3
Original line number Diff line number Diff line
@@ -677,9 +677,18 @@ directory and a subdirectory on :envvar:`PYTHONPATH`. Refer to the section on
the new project layout in the :doc:`1.4 release notes </releases/1.4>` for
migration instructions.

You should make sure that your project doesn't import models from applications
that aren't in :setting:`INSTALLED_APPS`. Relations involving such models may
not be created properly. Future versions of Django may forbid this entirely.
You should make sure that:

* All models are defined in applications that are listed in
  :setting:`INSTALLED_APPS` or have an explicit
  :attr:`~django.db.models.Options.app_label`.

* Models aren't imported as a side-effect of loading their application.
  Specifically, you shouldn't import models in the root module of an
  application nor in the module that define its configuration class.

Django will enforce these requirements as of version 1.9, after a deprecation
period.

Subclassing AppCommand
^^^^^^^^^^^^^^^^^^^^^^
+6 −1
Original line number Diff line number Diff line
@@ -130,6 +130,11 @@ def setup(verbosity, test_labels):
        'django.contrib.comments is deprecated and will be removed before Django 1.8.',
        DeprecationWarning
    )
    warnings.filterwarnings(
        'ignore',
        'Model class django.contrib.comments.models.*supported in Django 1.9.',
        PendingDeprecationWarning
    )
    # Load all the ALWAYS_INSTALLED_APPS.
    django.setup()

@@ -169,8 +174,8 @@ def setup(verbosity, test_labels):
            if module_label not in settings.INSTALLED_APPS:
                settings.INSTALLED_APPS.append(module_label)
            app_config = AppConfig.create(module_label)
            app_config.import_models(apps.all_models[app_config.label])
            apps.app_configs[app_config.label] = app_config
            app_config.import_models(apps.all_models[app_config.label])
            apps.clear_cache()

    return state