Commits

Anonymous committed 6389add

[soc2010/app-loading] implement APP_CLASSES setting

  • Participants
  • Parent commits e1b4cf4
  • Branches soc2010/app-loading

Comments (0)

Files changed (4)

django/conf/global_settings.py

 EMAIL_HOST_PASSWORD = ''
 EMAIL_USE_TLS = False
 
+# List of strings representing installed app classes.
+APP_CLASSES = ()
+
 # List of strings representing installed apps.
 INSTALLED_APPS = ()
 

django/core/apps.py

         return self.name
 
     def __repr__(self):
-        return '<App: %s>' % self.name
+        return '<%s: %s>' % (self.__class__.__name__, self.name)
 
 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)
         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.
         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
+        app_module = import_module(app_name)
 
         # check if an app instance with that name already exists
         app_instance = self.find_app(app_name)
                 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
         self.nesting_level -= 1
         app_instance.models_module = models
         return models
-
+    
     def find_app(self, name):
         "Returns the App instance that matches name"
         if '.' in name:
         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

django/db/models/options.py

         # 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)
-            self.db_table = "%s_%s" % (app_instance.db_prefix, self.module_name)
+            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())
 
     def _prepare(self, model):

tests/appcachetests/runtests.py

 
     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. 
         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):
     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')
         """
         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):
         """
         """
         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"""