Fixed #21711 -- Enforced unicity of model names.
This commit is contained in:
parent
f5f7617167
commit
f630373b92
|
@ -185,7 +185,6 @@ class Apps(object):
|
||||||
# call get_app_config().
|
# call get_app_config().
|
||||||
model_name = model._meta.model_name
|
model_name = model._meta.model_name
|
||||||
app_models = self.all_models[app_label]
|
app_models = self.all_models[app_label]
|
||||||
# Defensive check for extra safety.
|
|
||||||
if model_name in app_models:
|
if model_name in app_models:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Conflicting '%s' models in application '%s': %s and %s." %
|
"Conflicting '%s' models in application '%s': %s and %s." %
|
||||||
|
|
|
@ -162,12 +162,6 @@ class ModelBase(type):
|
||||||
new_class._default_manager = new_class._default_manager._copy_to_model(new_class)
|
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)
|
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.
|
# Add all attributes to the class.
|
||||||
for obj_name, obj in attrs.items():
|
for obj_name, obj in attrs.items():
|
||||||
new_class.add_to_class(obj_name, obj)
|
new_class.add_to_class(obj_name, obj)
|
||||||
|
@ -285,13 +279,8 @@ class ModelBase(type):
|
||||||
return new_class
|
return new_class
|
||||||
|
|
||||||
new_class._prepare()
|
new_class._prepare()
|
||||||
|
|
||||||
new_class._meta.apps.register_model(new_class._meta.app_label, new_class)
|
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
|
return new_class
|
||||||
# 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)
|
|
||||||
|
|
||||||
def copy_managers(cls, base_managers):
|
def copy_managers(cls, base_managers):
|
||||||
# This is in-place sorting of an Options attribute, but that's fine.
|
# This is in-place sorting of an Options attribute, but that's fine.
|
||||||
|
|
|
@ -7,6 +7,7 @@ circular import difficulties.
|
||||||
"""
|
"""
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.apps import apps
|
||||||
from django.db.backends import utils
|
from django.db.backends import utils
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
from django.utils import tree
|
from django.utils import tree
|
||||||
|
@ -185,23 +186,29 @@ def deferred_class_factory(model, attrs):
|
||||||
being replaced with DeferredAttribute objects. The "pk_value" ties the
|
being replaced with DeferredAttribute objects. The "pk_value" ties the
|
||||||
deferred attributes to a particular instance of the model.
|
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
|
# 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
|
# the name using the passed in attrs. It's OK to reuse an existing class
|
||||||
# object if the attrs are identical.
|
# object if the attrs are identical.
|
||||||
name = "%s_Deferred_%s" % (model.__name__, '_'.join(sorted(list(attrs))))
|
name = "%s_Deferred_%s" % (model.__name__, '_'.join(sorted(list(attrs))))
|
||||||
name = utils.truncate_name(name, 80, 32)
|
name = utils.truncate_name(name, 80, 32)
|
||||||
|
|
||||||
|
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 = dict((attr, DeferredAttribute(attr, model)) for attr in attrs)
|
||||||
overrides["Meta"] = Meta
|
overrides["Meta"] = Meta
|
||||||
overrides["__module__"] = model.__module__
|
overrides["__module__"] = model.__module__
|
||||||
overrides["_deferred"] = True
|
overrides["_deferred"] = True
|
||||||
return type(str(name), (model,), overrides)
|
return type(str(name), (model,), overrides)
|
||||||
|
|
||||||
|
|
||||||
# The above function is also used to unpickle model instances with deferred
|
# The above function is also used to unpickle model instances with deferred
|
||||||
# fields.
|
# fields.
|
||||||
deferred_class_factory.__safe_for_unpickling__ = True
|
deferred_class_factory.__safe_for_unpickling__ = True
|
||||||
|
|
|
@ -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
|
:class:`~django.apps.AppConfig.label` there. You should then adjust your code
|
||||||
wherever it references this application or its models with the old label.
|
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
|
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
|
that aren't in :setting:`INSTALLED_APPS`. Relations involving such models may
|
||||||
not be created properly. Future versions of Django may forbid this entirely.
|
not be created properly. Future versions of Django may forbid this entirely.
|
||||||
|
|
Loading…
Reference in New Issue