Fixed #23621 -- Warn for duplicate models when a module is reloaded.
Previously a RuntimeError was raised every time two models clashed in the app registry. This prevented reloading a module in a REPL; while it's not recommended to do so, we decided not to forbid this use-case by turning the error into a warning. Thanks @dfunckt and Sergey Pashinin for the initial patches.
This commit is contained in:
parent
4bf86d25e5
commit
8c4ca16c65
|
@ -208,6 +208,12 @@ class Apps(object):
|
||||||
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]
|
||||||
if model_name in app_models:
|
if model_name in app_models:
|
||||||
|
if (model.__name__ == app_models[model_name].__name__ and
|
||||||
|
model.__module__ == app_models[model_name].__module__):
|
||||||
|
warnings.warn(
|
||||||
|
"Model '%s.%s' was already registered." % (model_name, app_label),
|
||||||
|
RuntimeWarning, stacklevel=2)
|
||||||
|
else:
|
||||||
raise RuntimeError(
|
raise RuntimeError(
|
||||||
"Conflicting '%s' models in application '%s': %s and %s." %
|
"Conflicting '%s' models in application '%s': %s and %s." %
|
||||||
(model_name, app_label, app_models[model_name], model))
|
(model_name, app_label, app_models[model_name], model))
|
||||||
|
|
|
@ -3,6 +3,7 @@ from __future__ import unicode_literals
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
from unittest import skipUnless
|
from unittest import skipUnless
|
||||||
|
import warnings
|
||||||
|
|
||||||
from django.apps import apps, AppConfig
|
from django.apps import apps, AppConfig
|
||||||
from django.apps.registry import Apps
|
from django.apps.registry import Apps
|
||||||
|
@ -208,6 +209,41 @@ class AppsTests(TestCase):
|
||||||
apps.get_model("apps", "SouthPonies")
|
apps.get_model("apps", "SouthPonies")
|
||||||
self.assertEqual(new_apps.get_model("apps", "SouthPonies"), temp_model)
|
self.assertEqual(new_apps.get_model("apps", "SouthPonies"), temp_model)
|
||||||
|
|
||||||
|
def test_model_clash(self):
|
||||||
|
"""
|
||||||
|
Test for behavior when two models clash in the app registry.
|
||||||
|
"""
|
||||||
|
new_apps = Apps(["apps"])
|
||||||
|
meta_contents = {
|
||||||
|
'app_label': "apps",
|
||||||
|
'apps': new_apps,
|
||||||
|
}
|
||||||
|
|
||||||
|
body = {}
|
||||||
|
body['Meta'] = type(str("Meta"), tuple(), meta_contents)
|
||||||
|
body['__module__'] = TotallyNormal.__module__
|
||||||
|
type(str("SouthPonies"), (models.Model,), body)
|
||||||
|
|
||||||
|
# When __name__ and __module__ match we assume the module
|
||||||
|
# was reloaded and issue a warning. This use-case is
|
||||||
|
# useful for REPL. Refs #23621.
|
||||||
|
body = {}
|
||||||
|
body['Meta'] = type(str("Meta"), tuple(), meta_contents)
|
||||||
|
body['__module__'] = TotallyNormal.__module__
|
||||||
|
with warnings.catch_warnings(record=True) as w:
|
||||||
|
type(str("SouthPonies"), (models.Model,), body)
|
||||||
|
self.assertEqual(len(w), 1)
|
||||||
|
self.assertTrue(issubclass(w[-1].category, RuntimeWarning))
|
||||||
|
self.assertEqual(str(w[-1].message), "Model 'southponies.apps' was already registered.")
|
||||||
|
|
||||||
|
# If it doesn't appear to be a reloaded module then we expect
|
||||||
|
# a RuntimeError.
|
||||||
|
body = {}
|
||||||
|
body['Meta'] = type(str("Meta"), tuple(), meta_contents)
|
||||||
|
body['__module__'] = TotallyNormal.__module__ + '.whatever'
|
||||||
|
with six.assertRaisesRegex(self, RuntimeError,
|
||||||
|
"Conflicting 'southponies' models in application 'apps':.*"):
|
||||||
|
type(str("SouthPonies"), (models.Model,), body)
|
||||||
|
|
||||||
class Stub(object):
|
class Stub(object):
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
|
|
Loading…
Reference in New Issue