1
0
mirror of https://github.com/django/django.git synced 2025-07-04 09:49:12 +00:00

[soc2010/app-loading] implement APP_CLASSES setting

git-svn-id: http://code.djangoproject.com/svn/django/branches/soc2010/app-loading@13759 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Arthur Koziel 2010-09-12 05:34:58 +00:00
parent 574424f40d
commit 11a32d6011
4 changed files with 41 additions and 30 deletions

View File

@ -170,6 +170,9 @@ EMAIL_HOST_USER = ''
EMAIL_HOST_PASSWORD = ''
EMAIL_USE_TLS = False
# List of strings representing installed app classes.
APP_CLASSES = ()
# List of strings representing installed apps.
INSTALLED_APPS = ()

View File

@ -33,7 +33,7 @@ class App(object):
return self.name
def __repr__(self):
return '<App: %s>' % self.name
return '<%s: %s>' % (self.__class__.__name__, self.name)
class AppCache(object):
"""
@ -78,10 +78,19 @@ class AppCache(object):
try:
if self.loaded:
return
for app_name in settings.APP_CLASSES:
if app_name in self.handled:
continue
app_module, app_classname = app_name.rsplit('.', 1)
app_module = import_module(app_module)
app_class = getattr(app_module, app_classname)
app_name = app_name.rsplit('.', 2)[0]
self.load_app(app_name, True, app_class)
for app_name in settings.INSTALLED_APPS:
if app_name in self.handled:
continue
self.load_app(app_name, True)
if not self.nesting_level:
for app_name in self.postponed:
self.load_app(app_name)
@ -111,7 +120,7 @@ class AppCache(object):
finally:
self.write_lock.release()
def load_app(self, app_name, can_postpone=False):
def load_app(self, app_name, can_postpone=False, app_class=App):
"""
Loads the app with the provided fully qualified name, and returns the
model module.
@ -119,20 +128,7 @@ class AppCache(object):
self.handled[app_name] = None
self.nesting_level += 1
try:
app_module = import_module(app_name)
except ImportError:
# If the import fails, we assume it was because an path to a
# class was passed (e.g. "foo.bar.MyApp")
# We split the app_name by the rightmost dot to get the path
# and classname, and then try importing it again
if not '.' in app_name:
raise
app_name, app_classname = app_name.rsplit('.', 1)
app_module = import_module(app_name)
app_class = getattr(app_module, app_classname)
else:
app_class = App
# check if an app instance with that name already exists
app_instance = self.find_app(app_name)
@ -144,10 +140,11 @@ class AppCache(object):
app_instance_name = app_name
app_instance = app_class(app_instance_name)
app_instance.module = app_module
app_instance.path = app_name
self.app_instances.append(app_instance)
self.installed_apps.append(app_name)
# check if the app instance specifies a path to models
# Check if the app instance specifies a path to models
# if not, we use the models.py file from the package dir
try:
models_path = app_instance.models_path
@ -211,9 +208,9 @@ class AppCache(object):
self._populate()
self.write_lock.acquire()
try:
for app_name in self.installed_apps:
if app_label == app_name.split('.')[-1]:
mod = self.load_app(app_name, False)
for app in self.app_instances:
if app_label == app.name:
mod = self.load_app(app.path, False)
if mod is None:
if emptyOK:
return None

View File

@ -99,6 +99,12 @@ class Options(object):
# If the db_table wasn't provided, use the db_prefix + module_name.
if not self.db_table:
app_instance = cache.find_app(self.app_label)
if not app_instance:
# use the app label when no app instance was found, this
# can happen when the app cache is not initialized but the
# model is imported
self.db_table = "%s_%s" % (self.app_label, self.module_name)
else:
self.db_table = "%s_%s" % (app_instance.db_prefix, self.module_name)
self.db_table = truncate_name(self.db_table, connection.ops.max_name_length())

View File

@ -18,10 +18,13 @@ class AppCacheTestCase(unittest.TestCase):
def setUp(self):
self.old_installed_apps = settings.INSTALLED_APPS
self.old_app_classes = settings.APP_CLASSES
settings.APP_CLASSES = ()
settings.INSTALLED_APPS = ()
def tearDown(self):
settings.INSTALLED_APPS = self.old_installed_apps
settings.APP_CLASSES = self.old_app_classes
# The appcache imports models modules. We need to delete the
# imported module from sys.modules after the test has run.
@ -102,7 +105,7 @@ class GetAppsTests(AppCacheTestCase):
Test that an exception is raised if two app instances
have the same db_prefix attribute
"""
settings.INSTALLED_APPS = ('nomodel_app.MyApp', 'model_app.MyOtherApp',)
settings.APP_CLASSES = ('nomodel_app.MyApp', 'model_app.MyOtherApp',)
self.assertRaises(ImproperlyConfigured, cache.get_apps)
class GetAppTests(AppCacheTestCase):
@ -264,10 +267,10 @@ class LoadAppTests(AppCacheTestCase):
def test_custom_app(self):
"""
Test that a custom app instance is created if the function
gets passed a classname
gets passed a custom app class
"""
from nomodel_app import MyApp
rv = cache.load_app('nomodel_app.MyApp')
rv = cache.load_app('nomodel_app', False, MyApp)
app = cache.app_instances[0]
self.assertEqual(len(cache.app_instances), 1)
self.assertEqual(app.name, 'nomodel_app')
@ -278,10 +281,11 @@ class LoadAppTests(AppCacheTestCase):
"""
Test that custom models are imported correctly
"""
rv = cache.load_app('model_app.MyApp')
from nomodel_app import MyApp
rv = cache.load_app('model_app', False, MyApp)
app = cache.app_instances[0]
self.assertEqual(app.models_module.__name__, 'model_app.othermodels')
self.assertEqual(rv.__name__, 'model_app.othermodels')
self.assertEqual(app.models_module.__name__, 'model_app.models')
self.assertEqual(rv.__name__, 'model_app.models')
def test_twice(self):
"""
@ -304,10 +308,11 @@ class LoadAppTests(AppCacheTestCase):
"""
Test that the installed_apps attribute is populated correctly
"""
settings.INSTALLED_APPS = ('model_app', 'nomodel_app.MyApp',)
settings.APP_CLASSES = ('nomodel_app.MyApp',)
settings.INSTALLED_APPS = ('model_app',)
# populate cache
cache.get_app_errors()
self.assertEqual(cache.installed_apps, ['model_app', 'nomodel_app',])
self.assertEqual(cache.installed_apps, ['nomodel_app', 'model_app',])
class RegisterModelsTests(AppCacheTestCase):
"""Tests for the register_models function"""