Fixed #21711 -- Enforced unicity of model names.

This commit is contained in:
Aymeric Augustin 2014-01-05 09:32:22 +01:00
parent f5f7617167
commit f630373b92
4 changed files with 24 additions and 23 deletions

View File

@ -185,7 +185,6 @@ class Apps(object):
# call get_app_config().
model_name = model._meta.model_name
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." %

View File

@ -162,12 +162,6 @@ class ModelBase(type):
new_class._default_manager = new_class._default_manager._copy_to_model(new_class)
new_class._base_manager = new_class._base_manager._copy_to_model(new_class)
# Bail out early if we have already created this class.
try:
return new_class._meta.apps.get_registered_model(new_class._meta.app_label, name)
except LookupError:
pass
# Add all attributes to the class.
for obj_name, obj in attrs.items():
new_class.add_to_class(obj_name, obj)
@ -285,13 +279,8 @@ class ModelBase(type):
return new_class
new_class._prepare()
new_class._meta.apps.register_model(new_class._meta.app_label, new_class)
# Because of the way imports happen (recursively), we may or may not be
# the first time this model tries to register with the framework. There
# should only be one class for each model, so we always return the
# registered version.
return new_class._meta.apps.get_registered_model(new_class._meta.app_label, name)
return new_class
def copy_managers(cls, base_managers):
# This is in-place sorting of an Options attribute, but that's fine.

View File

@ -7,6 +7,7 @@ circular import difficulties.
"""
from __future__ import unicode_literals
from django.apps import apps
from django.db.backends import utils
from django.utils import six
from django.utils import tree
@ -185,22 +186,28 @@ def deferred_class_factory(model, attrs):
being replaced with DeferredAttribute objects. The "pk_value" ties the
deferred attributes to a particular instance of the model.
"""
class Meta:
proxy = True
app_label = model._meta.app_label
# The app registry wants a unique name for each model, otherwise the new
# class won't be created (we get an old one back). Therefore, we generate
# class won't be created (we get an exception). Therefore, we generate
# the name using the passed in attrs. It's OK to reuse an existing class
# object if the attrs are identical.
name = "%s_Deferred_%s" % (model.__name__, '_'.join(sorted(list(attrs))))
name = utils.truncate_name(name, 80, 32)
overrides = dict((attr, DeferredAttribute(attr, model)) for attr in attrs)
overrides["Meta"] = Meta
overrides["__module__"] = model.__module__
overrides["_deferred"] = True
return type(str(name), (model,), overrides)
try:
return apps.get_model(model._meta.app_label, name)
except LookupError:
class Meta:
proxy = True
app_label = model._meta.app_label
overrides = dict((attr, DeferredAttribute(attr, model)) for attr in attrs)
overrides["Meta"] = Meta
overrides["__module__"] = model.__module__
overrides["_deferred"] = True
return type(str(name), (model,), overrides)
# The above function is also used to unpickle model instances with deferred
# fields.

View File

@ -664,6 +664,12 @@ If you have two apps with the same label, you should create an
:class:`~django.apps.AppConfig.label` there. You should then adjust your code
wherever it references this application or its models with the old label.
It isn't possible to import the same model twice through different paths any
more. As of Django 1.6, this may happen only if you're manually putting a
directory and a subdirectory on :envvar:`PYTHONPATH`. Refer to the section on
the new project layout in the :doc:`1.4 release notes </releases/1.4>` for
migration instructions.
You should make sure that your project doesn't import models from applications
that aren't in :setting:`INSTALLED_APPS`. Relations involving such models may
not be created properly. Future versions of Django may forbid this entirely.