1. Luke Plant
  2. django

Commits

art...@bcc190cf-cafb-0310-a4f2-bffc1f526a37  committed de9f7ab

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

  • Participants
  • Parent commits 33925a8
  • Branches soc2010/app-loading

Comments (0)

Files changed (3)

File django/core/apps.py

View file
  • Ignore whitespace
         installed_apps = [],
 
         # 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 --
         loaded = False,
             if not self.nesting_level:
                 for app_name in self.postponed:
                     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.unbound_models = {}
         finally:
             self.write_lock.release()
 
             if app.name == name:
                 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):
         """
         Returns true if the model cache is fully populated.
         if seed_cache:
             self._populate()
         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:
                 if model_name.lower() == model._meta.object_name.lower():
                     return model
+        else:
+            return self.unbound_models.get(app_label, {}).get(
+                    model_name.lower())
 
     def register_models(self, app_label, *models):
         """
         Register a set of models as belonging to an app.
         """
         app_instance = self.find_app(app_label)
-        if not app_instance:
-            raise ImproperlyConfigured('Could not find App instance with label "%s". '
-                                       'Please check your INSTALLED_APPS setting'
-                                       % app_label)
+        if self.app_cache_ready() and not app_instance:
+            raise ImproperlyConfigured(
+                'Could not find an app instance with the label "%s". '
+                'Please check your INSTALLED_APPS setting' % app_label)
+
         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_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:
                 # The same model may be imported via different paths (e.g.
                 # appname.models and project.appname.models). We use the source
                 # comparing.
                 if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]:
                     continue
-            model_dict[model_name] = model
-            app_instance.models.append(model)
+            if self.app_cache_ready():
+                app_instance.models.append(model)
+            else:
+                model_dict[model_name] = model
         self._get_models_cache.clear()
 
 cache = AppCache()

File tests/appcachetests/runtests.py

View file
  • Ignore whitespace
         # To detect which model modules have been imported, we go through
         # all loaded model classes and remove their respective module 
         # from sys.modules
-        for app in cache.app_models.itervalues():
+        for app in cache.unbound_models.itervalues():
             for name in app.itervalues():
                 module = name.__module__
                 if module in sys.modules:
                     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
         # because thread.RLock is un(deep)copyable
-        cache.app_models = SortedDict()
+        cache.unbound_models = {}
         cache.app_instances = []
         cache.installed_apps = []
 
         from django.contrib.flatpages.models import Site, FlatPage
         self.assertEqual(len(models), 3)
         self.assertEqual(models[0], Site)
-        self.assertEqual(models[1].__name__, 'FlatPage_sites')
-        self.assertEqual(models[2], FlatPage)
+        self.assertEqual(models[1], FlatPage)
+        self.assertEqual(models[2].__name__, 'FlatPage_sites')
         self.assertTrue(cache.app_cache_ready())
 
-    def test_include_deferred(self):
-        """TODO!"""
-
 class GetModelTests(AppCacheTestCase):
     """Tests for the get_model function"""
 
-    def test_get_model(self):
-        """Test that the correct model is returned"""
-        settings.INSTALLED_APPS = ('django.contrib.sites',
-                                   'django.contrib.flatpages',)
-        rv = cache.get_model('flatpages', 'FlatPage')
-        from django.contrib.flatpages.models import FlatPage
-        self.assertEqual(rv, FlatPage)
+    def test_seeded(self):
+        """
+        Test that the correct model is returned when the cache is seeded
+        """
+        settings.INSTALLED_APPS = ('model_app',)
+        rv = cache.get_model('model_app', 'Person')
+        self.assertEqual(rv.__name__, 'Person')
         self.assertTrue(cache.app_cache_ready())
 
-    def test_invalid(self):
-        """Test that None is returned if an app/model does not exist"""
-        self.assertEqual(cache.get_model('foo', 'bar'), None)
+    def test_seeded_invalid(self):
+        """
+        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())
 
-    def test_without_seeding(self):
-        """Test that None is returned if the cache is not seeded"""
-        settings.INSTALLED_APPS = ('django.contrib.flatpages',)
-        rv = cache.get_model('flatpages', 'FlatPage', seed_cache=False)
+    def test_unseeded(self):
+        """
+        Test that the correct model is returned when the cache is
+        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.assertFalse(cache.app_cache_ready())
 
 class RegisterModelsTests(AppCacheTestCase):
     """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
-        app instance
+        Test that the models are attached to the correct app instance
+        in a seeded cache
         """
-        # We don't need to call the register_models method. Importing the 
-        # models.py file will suffice. This is done in the load_app function
-        # The ModelBase will call the register_models method
-        cache.load_app('model_app')
-        app = cache.app_instances[0]
-        self.assertEqual(len(cache.app_instances), 1)
-        self.assertEqual(app.models[0].__name__, 'Person')
+        settings.INSTALLED_APPS = ('model_app',)
+        cache.get_app_errors()
+        self.assertTrue(cache.app_cache_ready())
+        app_models = cache.app_instances[0].models
+        self.assertEqual(len(app_models), 1)
+        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
-        to an app that isn't listed in INSTALLED_APPS.
+        Test that an exception is raised if the cache is seeded and models
+        are tried to be attached to an app instance that doesn't exist
         """
-        try:
-            from model_app.models import Person
-        except ImproperlyConfigured:
-            pass
-        else:
-            self.fail('ImproperlyConfigured not raised')
+        settings.INSTALLED_APPS = ('model_app',)
+        cache.get_app_errors()
+        self.assertTrue(cache.app_cache_ready())
+        from model_app.models import Person
+        self.assertRaises(ImproperlyConfigured, cache.register_models,
+                '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__':
     unittest.main()

File tests/appcachetests/same_label/model_app/models.py

View file
  • Ignore whitespace
 from django.db import models
 
-class User(models.Model):
+class Person(models.Model):
     first_name = models.CharField(max_length=30)
     last_name = models.CharField(max_length=30)