Skip to content


Subversion checkout URL

You can clone with
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 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
19 django/db/models/
@@ -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)
12 tests/regressiontests/swappable_models/
@@ -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:
+'Swappable model names should be case insensitive.')
+ self.assertIsNone(Article._meta.swapped)

0 comments on commit b760700

Please sign in to comment.
Something went wrong with that request. Please try again.