From 48fe6099c06cc84d666d4032d746c53be43ee196 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sat, 12 Feb 2011 15:15:44 +0000 Subject: [PATCH] [1.2.X] Fixed #13987 -- Ensure that the primary key is set correctly for all models that have concrete-abstract-concrete inheritance, not just the first model. Thanks to Aramgutang for the report and patch. Backport of r15498 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.2.X@15499 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/models/options.py | 6 +++++ .../model_inheritance_regress/models.py | 17 +++++++++++++ .../model_inheritance_regress/tests.py | 24 +++++++++++++++++-- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/django/db/models/options.py b/django/db/models/options.py index 3196a41ff2..5ff4b73161 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -118,6 +118,12 @@ class Options(object): # Promote the first parent link in lieu of adding yet another # field. field = self.parents.value_for_index(0) + # Look for a local field with the same name as the + # first parent link. If a local field has already been + # created, use it instead of promoting the parent + already_created = [fld for fld in self.local_fields if fld.name == field.name] + if already_created: + field = already_created[0] field.primary_key = True self.setup_pk(field) else: diff --git a/tests/regressiontests/model_inheritance_regress/models.py b/tests/regressiontests/model_inheritance_regress/models.py index 787f163349..bb5d77c51f 100644 --- a/tests/regressiontests/model_inheritance_regress/models.py +++ b/tests/regressiontests/model_inheritance_regress/models.py @@ -146,3 +146,20 @@ class BachelorParty(AbstractEvent): class MessyBachelorParty(BachelorParty): pass + +# Check concrete -> abstract -> concrete inheritance +class SearchableLocation(models.Model): + keywords = models.CharField(max_length=256) + +class Station(SearchableLocation): + name = models.CharField(max_length=128) + + class Meta: + abstract = True + +class BusStation(Station): + bus_routes = models.CommaSeparatedIntegerField(max_length=128) + inbound = models.BooleanField() + +class TrainStation(Station): + zone = models.IntegerField() diff --git a/tests/regressiontests/model_inheritance_regress/tests.py b/tests/regressiontests/model_inheritance_regress/tests.py index dac2cb5de5..1bb147e17c 100644 --- a/tests/regressiontests/model_inheritance_regress/tests.py +++ b/tests/regressiontests/model_inheritance_regress/tests.py @@ -11,7 +11,7 @@ from models import (Place, Restaurant, ItalianRestaurant, ParkingLot, ParkingLot2, ParkingLot3, Supplier, Wholesaler, Child, SelfRefParent, SelfRefChild, ArticleWithAuthor, M2MChild, QualityControl, DerivedM, Person, BirthdayParty, BachelorParty, MessyBachelorParty, - InternalCertificationAudit) + InternalCertificationAudit, BusStation, TrainStation) class ModelInheritanceTest(TestCase): @@ -358,7 +358,7 @@ class ModelInheritanceTest(TestCase): parties = list(p4.bachelorparty_set.all()) self.assertEqual(parties, [bachelor, messy_parent]) - def test_11369(self): + def test_abstract_verbose_name_plural_inheritance(self): """ verbose_name_plural correctly inherited from ABC if inheritance chain includes an abstract model. @@ -386,3 +386,23 @@ class ModelInheritanceTest(TestCase): ], attrgetter("pk") ) + + def test_concrete_abstract_concrete_pk(self): + """ + Primary key set correctly with concrete->abstract->concrete inheritance. + """ + # Regression test for #13987: Primary key is incorrectly determined + # when more than one model has a concrete->abstract->concrete + # inheritance hierarchy. + self.assertEquals( + len([field for field in BusStation._meta.local_fields + if field.primary_key]), + 1 + ) + self.assertEquals( + len([field for field in TrainStation._meta.local_fields + if field.primary_key]), + 1 + ) + self.assertIs(BusStation._meta.pk.model, BusStation) + self.assertIs(TrainStation._meta.pk.model, TrainStation)