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.
This commit is contained in:
parent
81a5e35c8d
commit
bbdf01e00a
|
@ -53,7 +53,7 @@ class AppConfig(object):
|
||||||
self.models = None
|
self.models = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return '<AppConfig: %s>' % self.label
|
return '<%s: %s>' % (self.__class__.__name__, self.label)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def create(cls, entry):
|
def create(cls, entry):
|
||||||
|
|
|
@ -27,9 +27,8 @@ class Apps(object):
|
||||||
if master and hasattr(sys.modules[__name__], 'apps'):
|
if master and hasattr(sys.modules[__name__], 'apps'):
|
||||||
raise RuntimeError("You may create only one master registry.")
|
raise RuntimeError("You may create only one master registry.")
|
||||||
|
|
||||||
# When master is set to False, the registry isn't populated from
|
# When master is set to False, the registry ignores the only_installed
|
||||||
# INSTALLED_APPS and ignores the only_installed arguments to
|
# arguments to get_model[s].
|
||||||
# get_model[s].
|
|
||||||
self.master = master
|
self.master = master
|
||||||
|
|
||||||
# Mapping of app labels => model names => model classes. Every time a
|
# Mapping of app labels => model names => model classes. Every time a
|
||||||
|
@ -48,9 +47,9 @@ class Apps(object):
|
||||||
# set_available_apps and set_installed_apps.
|
# set_available_apps and set_installed_apps.
|
||||||
self.stored_app_configs = []
|
self.stored_app_configs = []
|
||||||
|
|
||||||
# Internal flags used when populating the master registry.
|
# Internal flags used when populating the registry.
|
||||||
self._apps_loaded = not self.master
|
self._apps_loaded = False
|
||||||
self._models_loaded = not self.master
|
self._models_loaded = False
|
||||||
|
|
||||||
# Pending lookups for lazy relations.
|
# Pending lookups for lazy relations.
|
||||||
self._pending_lookups = {}
|
self._pending_lookups = {}
|
||||||
|
@ -82,8 +81,11 @@ class Apps(object):
|
||||||
# Therefore we simply import them sequentially.
|
# Therefore we simply import them sequentially.
|
||||||
if installed_apps is None:
|
if installed_apps is None:
|
||||||
installed_apps = settings.INSTALLED_APPS
|
installed_apps = settings.INSTALLED_APPS
|
||||||
for app_name in installed_apps:
|
for entry in installed_apps:
|
||||||
app_config = AppConfig.create(app_name)
|
if isinstance(entry, AppConfig):
|
||||||
|
app_config = entry
|
||||||
|
else:
|
||||||
|
app_config = AppConfig.create(entry)
|
||||||
self.app_configs[app_config.label] = app_config
|
self.app_configs[app_config.label] = app_config
|
||||||
|
|
||||||
self.get_models.cache_clear()
|
self.get_models.cache_clear()
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
from django.apps import AppConfig
|
||||||
from django.apps.registry import Apps
|
from django.apps.registry import Apps
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.db.models.options import DEFAULT_NAMES, normalize_unique_together
|
from django.db.models.options import DEFAULT_NAMES, normalize_unique_together
|
||||||
|
@ -33,6 +34,11 @@ class ProjectState(object):
|
||||||
"Turns the project state into actual models in a new Apps"
|
"Turns the project state into actual models in a new Apps"
|
||||||
if self.apps is None:
|
if self.apps is None:
|
||||||
self.apps = Apps()
|
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
|
# We keep trying to render the models in a loop, ignoring invalid
|
||||||
# base errors, until the size of the unrendered models doesn't
|
# base errors, until the size of the unrendered models doesn't
|
||||||
# decrease by at least one, meaning there's a base dependency loop/
|
# decrease by at least one, meaning there's a base dependency loop/
|
||||||
|
@ -68,6 +74,19 @@ class ProjectState(object):
|
||||||
return not (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):
|
class ModelState(object):
|
||||||
"""
|
"""
|
||||||
Represents a Django Model. We don't use the actual Model class
|
Represents a Django Model. We don't use the actual Model class
|
||||||
|
|
|
@ -50,8 +50,10 @@ class AppsTests(TestCase):
|
||||||
Tests the ready property of a registry other than the master.
|
Tests the ready property of a registry other than the master.
|
||||||
"""
|
"""
|
||||||
apps = Apps()
|
apps = Apps()
|
||||||
# Currently, non-master app registries are artificially considered
|
self.assertFalse(apps.ready)
|
||||||
# ready regardless of whether populate_models() has run.
|
apps.populate_apps([])
|
||||||
|
self.assertFalse(apps.ready)
|
||||||
|
apps.populate_models()
|
||||||
self.assertTrue(apps.ready)
|
self.assertTrue(apps.ready)
|
||||||
|
|
||||||
def test_bad_app_config(self):
|
def test_bad_app_config(self):
|
||||||
|
|
Loading…
Reference in New Issue