Browse Source

Simplified the implementation of register_model.

register_model is called exactly once in the entire Django code base, at the
bottom of ModelBase.__new__:

    new_class._meta.apps.register_model(new_class._meta.app_label, new_class)

ModelBase.__new__ exits prematurely 120 lines earlier (sigh) if a model with
the same name is already registered:

    if new_class._meta.apps.get_registered_model(new_class._meta.app_label, name):
        return

(This isn't the exact code, but it's equivalent.)

apps.register_model and apps.get_registered_model are essentially a setter and
a getter for apps.all_models, and apps.register_model is the only setter. As a
consequence, new_class._meta.apps.all_models cannot change in-between.

Considering that name == new_class.__name__, we can conclude that
register_model(app_label, model) is always called with such arguments that
get_registered_model(app_label, model.__name__) returns None.

Considering that model._meta.model_name == model.__name__.lower(), and looking
at the implementation of register_model and get_registered_model, this proves
that self.all_models[app_label] doesn't contain model._meta.model_name in
register_model, allowing us to simplify the implementation.
Aymeric Augustin 11 years ago
parent
commit
aff57793b4
1 changed files with 7 additions and 13 deletions
  1. 7 13
      django/apps/registry.py

+ 7 - 13
django/apps/registry.py

@@ -261,19 +261,13 @@ class Apps(object):
         # perform imports because of the risk of import loops. It mustn't
         # call get_app_config().
         model_name = model._meta.model_name
-        models = self.all_models[app_label]
-        if model_name in models:
-            # The same model may be imported via different paths (e.g.
-            # appname.models and project.appname.models). We use the source
-            # filename as a means to detect identity.
-            fname1 = os.path.abspath(upath(sys.modules[model.__module__].__file__))
-            fname2 = os.path.abspath(upath(sys.modules[models[model_name].__module__].__file__))
-            # Since the filename extension could be .py the first time and
-            # .pyc or .pyo the second time, ignore the extension when
-            # comparing.
-            if os.path.splitext(fname1)[0] == os.path.splitext(fname2)[0]:
-                return
-        models[model_name] = model
+        app_models = self.all_models[app_label]
+        # Defensive check for extra safety.
+        if model_name in app_models:
+            raise RuntimeError(
+                "Conflicting '%s' models in application '%s': %s and %s." %
+                (model_name, app_label, app_models[model_name], model))
+        app_models[model_name] = model
         self.get_models.cache_clear()
 
     def has_app(self, app_name):