Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Populated non-master app registries.

This removes the gap between the master app registry and ad-hoc app
registries created by the migration framework, specifically in terms
of behavior of the get_model[s] methods.

This commit contains a stealth feature that I'd rather not describe.
  • Loading branch information...
commit bbdf01e00aed1e86f6aaeba81065be21af35d415 1 parent 81a5e35
@aaugustin aaugustin authored
View
2  django/apps/base.py
@@ -53,7 +53,7 @@ def __init__(self, app_name, app_module):
self.models = None
def __repr__(self):
- return '<AppConfig: %s>' % self.label
+ return '<%s: %s>' % (self.__class__.__name__, self.label)
@classmethod
def create(cls, entry):
View
18 django/apps/registry.py
@@ -27,9 +27,8 @@ def __init__(self, master=False):
if master and hasattr(sys.modules[__name__], 'apps'):
raise RuntimeError("You may create only one master registry.")
- # When master is set to False, the registry isn't populated from
- # INSTALLED_APPS and ignores the only_installed arguments to
- # get_model[s].
+ # When master is set to False, the registry ignores the only_installed
+ # arguments to get_model[s].
self.master = master
# Mapping of app labels => model names => model classes. Every time a
@@ -48,9 +47,9 @@ def __init__(self, master=False):
# set_available_apps and set_installed_apps.
self.stored_app_configs = []
- # Internal flags used when populating the master registry.
- self._apps_loaded = not self.master
- self._models_loaded = not self.master
+ # Internal flags used when populating the registry.
+ self._apps_loaded = False
+ self._models_loaded = False
# Pending lookups for lazy relations.
self._pending_lookups = {}
@@ -82,8 +81,11 @@ def populate_apps(self, installed_apps=None):
# Therefore we simply import them sequentially.
if installed_apps is None:
installed_apps = settings.INSTALLED_APPS
- for app_name in installed_apps:
- app_config = AppConfig.create(app_name)
+ for entry in installed_apps:
+ if isinstance(entry, AppConfig):
+ app_config = entry
+ else:
+ app_config = AppConfig.create(entry)
self.app_configs[app_config.label] = app_config
self.get_models.cache_clear()
View
19 django/db/migrations/state.py
@@ -1,3 +1,4 @@
+from django.apps import AppConfig
from django.apps.registry import Apps
from django.db import models
from django.db.models.options import DEFAULT_NAMES, normalize_unique_together
@@ -33,6 +34,11 @@ def render(self):
"Turns the project state into actual models in a new Apps"
if self.apps is None:
self.apps = Apps()
+ # Populate the app registry with a stub for each application.
+ app_labels = set(model_state.app_label for model_state in self.models.values())
+ app_configs = [AppConfigStub(label) for label in sorted(app_labels)]
+ self.apps.populate_apps(app_configs)
+ self.apps.populate_models()
# We keep trying to render the models in a loop, ignoring invalid
# base errors, until the size of the unrendered models doesn't
# decrease by at least one, meaning there's a base dependency loop/
@@ -68,6 +74,19 @@ def __ne__(self, other):
return not (self == other)
+class AppConfigStub(AppConfig):
+ """
+ Stubs a Django AppConfig. Only provides a label and a dict of models.
+ """
+ def __init__(self, label):
+ self.label = label
+ self.path = None
+ super(AppConfigStub, self).__init__(None, None)
+
+ def import_models(self, all_models):
+ self.models = all_models
+
+
class ModelState(object):
"""
Represents a Django Model. We don't use the actual Model class
View
6 tests/apps/tests.py
@@ -50,8 +50,10 @@ def test_non_master_ready(self):
Tests the ready property of a registry other than the master.
"""
apps = Apps()
- # Currently, non-master app registries are artificially considered
- # ready regardless of whether populate_models() has run.
+ self.assertFalse(apps.ready)
+ apps.populate_apps([])
+ self.assertFalse(apps.ready)
+ apps.populate_models()
self.assertTrue(apps.ready)
def test_bad_app_config(self):
Please sign in to comment.
Something went wrong with that request. Please try again.