1
0
mirror of https://github.com/django/django.git synced 2025-07-04 17:59:13 +00:00

[soc2010/app-loading] register models als unbound if the cache is not initialized

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/app-loading@13576 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Arthur Koziel 2010-08-14 00:52:33 +00:00
parent 81dc507963
commit 3da601b606
3 changed files with 101 additions and 61 deletions

View File

@ -46,7 +46,7 @@ class AppCache(object):
installed_apps = [], installed_apps = [],
# Mapping of app_labels to a dictionary of model names to model code. # Mapping of app_labels to a dictionary of model names to model code.
app_models = SortedDict(), unbound_models = {},
# -- Everything below here is only used when populating the cache -- # -- Everything below here is only used when populating the cache --
loaded = False, loaded = False,
@ -79,7 +79,19 @@ class AppCache(object):
if not self.nesting_level: if not self.nesting_level:
for app_name in self.postponed: for app_name in self.postponed:
self.load_app(app_name) self.load_app(app_name)
# since the cache is still unseeded at this point
# all models have been stored as unbound models
# we need to assign the models to the app instances
for app_name, models in self.unbound_models.iteritems():
app_instance = self.find_app(app_name)
if not app_instance:
raise ImproperlyConfigured(
'Could not find an app instance for "%s"'
% app_label)
for model in models.itervalues():
app_instance.models.append(model)
self.loaded = True self.loaded = True
self.unbound_models = {}
finally: finally:
self.write_lock.release() self.write_lock.release()
@ -159,15 +171,6 @@ class AppCache(object):
if app.name == name: if app.name == name:
return app return app
def create_app(self, name):
"""create an app instance"""
name = name.split('.')[-1]
app = self.find_app(name)
if not app:
app = App(name)
self.app_instances.append(app)
return app
def app_cache_ready(self): def app_cache_ready(self):
""" """
Returns true if the model cache is fully populated. Returns true if the model cache is fully populated.
@ -259,25 +262,34 @@ class AppCache(object):
if seed_cache: if seed_cache:
self._populate() self._populate()
app = self.find_app(app_label) app = self.find_app(app_label)
if app: if self.app_cache_ready() and not app:
return
if cache.app_cache_ready():
for model in app.models: for model in app.models:
if model_name.lower() == model._meta.object_name.lower(): if model_name.lower() == model._meta.object_name.lower():
return model return model
else:
return self.unbound_models.get(app_label, {}).get(
model_name.lower())
def register_models(self, app_label, *models): def register_models(self, app_label, *models):
""" """
Register a set of models as belonging to an app. Register a set of models as belonging to an app.
""" """
app_instance = self.find_app(app_label) app_instance = self.find_app(app_label)
if not app_instance: if self.app_cache_ready() and not app_instance:
raise ImproperlyConfigured('Could not find App instance with label "%s". ' raise ImproperlyConfigured(
'Please check your INSTALLED_APPS setting' 'Could not find an app instance with the label "%s". '
% app_label) 'Please check your INSTALLED_APPS setting' % app_label)
for model in models: for model in models:
# Store as 'name: model' pair in a dictionary
# in the models list of the App instance
model_name = model._meta.object_name.lower() model_name = model._meta.object_name.lower()
model_dict = self.app_models.setdefault(app_label, SortedDict()) if self.app_cache_ready():
model_dict = dict([(model._meta.object_name.lower(), model)
for model in app_instance.models])
else:
model_dict = self.unbound_models.setdefault(app_label, {})
if model_name in model_dict: if model_name in model_dict:
# The same model may be imported via different paths (e.g. # The same model may be imported via different paths (e.g.
# appname.models and project.appname.models). We use the source # appname.models and project.appname.models). We use the source
@ -289,8 +301,10 @@ class AppCache(object):
# comparing. # comparing.
if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]: if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]:
continue continue
model_dict[model_name] = model if self.app_cache_ready():
app_instance.models.append(model) app_instance.models.append(model)
else:
model_dict[model_name] = model
self._get_models_cache.clear() self._get_models_cache.clear()
cache = AppCache() cache = AppCache()

View File

@ -32,15 +32,21 @@ class AppCacheTestCase(unittest.TestCase):
# To detect which model modules have been imported, we go through # To detect which model modules have been imported, we go through
# all loaded model classes and remove their respective module # all loaded model classes and remove their respective module
# from sys.modules # from sys.modules
for app in cache.app_models.itervalues(): for app in cache.unbound_models.itervalues():
for name in app.itervalues(): for name in app.itervalues():
module = name.__module__ module = name.__module__
if module in sys.modules: if module in sys.modules:
del sys.modules[module] del sys.modules[module]
for app in cache.app_instances:
for model in app.models:
module = model.__module__
if module in sys.modules:
del sys.modules[module]
# we cannot copy() the whole cache.__dict__ in the setUp function # we cannot copy() the whole cache.__dict__ in the setUp function
# because thread.RLock is un(deep)copyable # because thread.RLock is un(deep)copyable
cache.app_models = SortedDict() cache.unbound_models = {}
cache.app_instances = [] cache.app_instances = []
cache.installed_apps = [] cache.installed_apps = []
@ -178,34 +184,47 @@ class GetModelsTests(AppCacheTestCase):
from django.contrib.flatpages.models import Site, FlatPage from django.contrib.flatpages.models import Site, FlatPage
self.assertEqual(len(models), 3) self.assertEqual(len(models), 3)
self.assertEqual(models[0], Site) self.assertEqual(models[0], Site)
self.assertEqual(models[1].__name__, 'FlatPage_sites') self.assertEqual(models[1], FlatPage)
self.assertEqual(models[2], FlatPage) self.assertEqual(models[2].__name__, 'FlatPage_sites')
self.assertTrue(cache.app_cache_ready()) self.assertTrue(cache.app_cache_ready())
def test_include_deferred(self):
"""TODO!"""
class GetModelTests(AppCacheTestCase): class GetModelTests(AppCacheTestCase):
"""Tests for the get_model function""" """Tests for the get_model function"""
def test_get_model(self): def test_seeded(self):
"""Test that the correct model is returned""" """
settings.INSTALLED_APPS = ('django.contrib.sites', Test that the correct model is returned when the cache is seeded
'django.contrib.flatpages',) """
rv = cache.get_model('flatpages', 'FlatPage') settings.INSTALLED_APPS = ('model_app',)
from django.contrib.flatpages.models import FlatPage rv = cache.get_model('model_app', 'Person')
self.assertEqual(rv, FlatPage) self.assertEqual(rv.__name__, 'Person')
self.assertTrue(cache.app_cache_ready()) self.assertTrue(cache.app_cache_ready())
def test_invalid(self): def test_seeded_invalid(self):
"""Test that None is returned if an app/model does not exist""" """
self.assertEqual(cache.get_model('foo', 'bar'), None) Test that None is returned if a model was not registered
with the seeded cache
"""
rv = cache.get_model('model_app', 'Person')
self.assertEqual(rv, None)
self.assertTrue(cache.app_cache_ready()) self.assertTrue(cache.app_cache_ready())
def test_without_seeding(self): def test_unseeded(self):
"""Test that None is returned if the cache is not seeded""" """
settings.INSTALLED_APPS = ('django.contrib.flatpages',) Test that the correct model is returned when the cache is
rv = cache.get_model('flatpages', 'FlatPage', seed_cache=False) unseeded (but the model was registered using register_models)
"""
from model_app.models import Person
rv = cache.get_model('model_app', 'Person', seed_cache=False)
self.assertEqual(rv.__name__, 'Person')
self.assertFalse(cache.app_cache_ready())
def test_unseeded_invalid(self):
"""
Test that None is returned if a model was not registered
with the unseeded cache
"""
rv = cache.get_model('model_app', 'Person', seed_cache=False)
self.assertEqual(rv, None) self.assertEqual(rv, None)
self.assertFalse(cache.app_cache_ready()) self.assertFalse(cache.app_cache_ready())
@ -285,30 +304,37 @@ class LoadAppTests(AppCacheTestCase):
class RegisterModelsTests(AppCacheTestCase): class RegisterModelsTests(AppCacheTestCase):
"""Tests for the register_models function""" """Tests for the register_models function"""
def test_register_models(self): def test_seeded_cache(self):
""" """
Test that register_models attaches the models to an existing Test that the models are attached to the correct app instance
app instance in a seeded cache
""" """
# We don't need to call the register_models method. Importing the settings.INSTALLED_APPS = ('model_app',)
# models.py file will suffice. This is done in the load_app function cache.get_app_errors()
# The ModelBase will call the register_models method self.assertTrue(cache.app_cache_ready())
cache.load_app('model_app') app_models = cache.app_instances[0].models
app = cache.app_instances[0] self.assertEqual(len(app_models), 1)
self.assertEqual(len(cache.app_instances), 1) self.assertEqual(app_models[0].__name__, 'Person')
self.assertEqual(app.models[0].__name__, 'Person')
def test_app_not_installed(self): def test_seeded_cache_invalid_app(self):
""" """
Test that an exception is raised if models are tried to be registered Test that an exception is raised if the cache is seeded and models
to an app that isn't listed in INSTALLED_APPS. are tried to be attached to an app instance that doesn't exist
""" """
try: settings.INSTALLED_APPS = ('model_app',)
from model_app.models import Person cache.get_app_errors()
except ImproperlyConfigured: self.assertTrue(cache.app_cache_ready())
pass from model_app.models import Person
else: self.assertRaises(ImproperlyConfigured, cache.register_models,
self.fail('ImproperlyConfigured not raised') 'model_app_NONEXISTENT', *(Person,))
def test_unseeded_cache(self):
"""
Test that models can be registered with an unseeded cache
"""
from model_app.models import Person
self.assertFalse(cache.app_cache_ready())
self.assertEquals(cache.unbound_models['model_app']['person'], Person)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()

View File

@ -1,5 +1,5 @@
from django.db import models from django.db import models
class User(models.Model): class Person(models.Model):
first_name = models.CharField(max_length=30) first_name = models.CharField(max_length=30)
last_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30)