diff --git a/django/db/models/options.py b/django/db/models/options.py index 2f64c56b00..10617dc9e9 100644 --- a/django/db/models/options.py +++ b/django/db/models/options.py @@ -123,6 +123,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)