Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[1.5.x] Fixed #19401 -- Ensure that swappable model references are ca…

…se insensitive.

This is necessary because get_model() checks are case insensitive, and if the swapable check isn't, the
swappable logic gets tied up in knots with models that are partially swapped out.

Thanks to chris@cogdon.org for the report and extensive analysis, and Preston for his work on the draft patch.

Backport of c04c03d from trunk.
  • Loading branch information...
commit b7607003a543b11c62ad4d2ca1f8e12bd4b97b89 1 parent 9892919
@freakboy3742 freakboy3742 authored
View
19 django/db/models/options.py
@@ -231,12 +231,25 @@ def _swapped(self):
"""
Has this model been swapped out for another? If so, return the model
name of the replacement; otherwise, return None.
+
+ For historical reasons, model name lookups using get_model() are
+ case insensitive, so we make sure we are case insensitive here.
"""
if self.swappable:
- model_label = '%s.%s' % (self.app_label, self.object_name)
+ model_label = '%s.%s' % (self.app_label, self.object_name.lower())
swapped_for = getattr(settings, self.swappable, None)
- if swapped_for not in (None, model_label):
- return swapped_for
+ if swapped_for:
+ try:
+ swapped_label, swapped_object = swapped_for.split('.')
+ except ValueError:
+ # setting not in the format app_label.model_name
+ # raising ImproperlyConfigured here causes problems with
+ # test cleanup code - instead it is raised in get_user_model
+ # or as part of validation.
+ return swapped_for
+
+ if '%s.%s' % (swapped_label, swapped_object.lower()) not in (None, model_label):
+ return swapped_for
return None
swapped = property(_swapped)
View
12 tests/regressiontests/swappable_models/tests.py
@@ -9,6 +9,8 @@
from django.test import TestCase
from django.test.utils import override_settings
+from regressiontests.swappable_models.models import Article
+
class SwappableModelTests(TestCase):
def setUp(self):
@@ -44,3 +46,13 @@ def test_generated_data(self):
for ct in ContentType.objects.all()]
self.assertIn(('swappable_models', 'alternatearticle'), apps_models)
self.assertNotIn(('swappable_models', 'article'), apps_models)
+
+ @override_settings(TEST_ARTICLE_MODEL='swappable_models.article')
+ def test_case_insensitive(self):
+ "Model names are case insensitive. Check that model swapping honors this."
+ try:
+ Article.objects.all()
+ except AttributeError:
+ self.fail('Swappable model names should be case insensitive.')
+
+ self.assertIsNone(Article._meta.swapped)
Please sign in to comment.
Something went wrong with that request. Please try again.