summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaulo Alvarado <commonzenpython@gmail.com>2017-06-26 12:11:20 -0400
committerTim Graham <timograham@gmail.com>2017-06-26 12:11:20 -0400
commitc4329271607637373e42f081bd632e653aa99ea3 (patch)
tree17a6ef45036dc31ee79e9f7c76a3e442903ac170
parentfa283067c94546e38a7c4c3748c5fd31c58b7f22 (diff)
Fixed #26362 -- Fixed update of the inherited id field of an object when its parent changes.
-rw-r--r--django/db/models/fields/related_descriptors.py16
-rw-r--r--tests/model_inheritance_regress/tests.py37
2 files changed, 53 insertions, 0 deletions
diff --git a/django/db/models/fields/related_descriptors.py b/django/db/models/fields/related_descriptors.py
index 0d7507f33f..80eaac26d4 100644
--- a/django/db/models/fields/related_descriptors.py
+++ b/django/db/models/fields/related_descriptors.py
@@ -277,6 +277,22 @@ class ForwardOneToOneDescriptor(ForwardManyToOneDescriptor):
return obj
return super().get_object(instance)
+ def __set__(self, instance, value):
+ super().__set__(instance, value)
+ # If the primary key is a link to a parent model and a parent instance
+ # is being set, update the value of the inherited pk(s).
+ if self.field.primary_key and self.field.remote_field.parent_link:
+ opts = instance._meta
+ # Inherited primary key fields from this object's base classes.
+ inherited_pk_fields = [
+ field for field in opts.concrete_fields
+ if field.primary_key and field.remote_field
+ ]
+ for field in inherited_pk_fields:
+ rel_model_pk_name = field.remote_field.model._meta.pk.attname
+ raw_value = getattr(value, rel_model_pk_name) if value is not None else None
+ setattr(instance, rel_model_pk_name, raw_value)
+
class ReverseOneToOneDescriptor:
"""
diff --git a/tests/model_inheritance_regress/tests.py b/tests/model_inheritance_regress/tests.py
index 7ed84cc5d0..b8f8ae6d87 100644
--- a/tests/model_inheritance_regress/tests.py
+++ b/tests/model_inheritance_regress/tests.py
@@ -527,3 +527,40 @@ class ModelInheritanceTest(TestCase):
restaurant = italian_restaurant.restaurant_ptr
self.assertEqual(restaurant.place_ptr.restaurant, restaurant)
self.assertEqual(restaurant.italianrestaurant, italian_restaurant)
+
+ def test_id_field_update_on_ancestor_change(self):
+ place1 = Place.objects.create(name='House of Pasta', address='944 Fullerton')
+ place2 = Place.objects.create(name='House of Pizza', address='954 Fullerton')
+ place3 = Place.objects.create(name='Burger house', address='964 Fullerton')
+ restaurant1 = Restaurant.objects.create(
+ place_ptr=place1,
+ serves_hot_dogs=True,
+ serves_pizza=False,
+ )
+ restaurant2 = Restaurant.objects.create(
+ place_ptr=place2,
+ serves_hot_dogs=True,
+ serves_pizza=False,
+ )
+
+ italian_restaurant = ItalianRestaurant.objects.create(
+ restaurant_ptr=restaurant1,
+ serves_gnocchi=True,
+ )
+ # Changing the parent of a restaurant changes the restaurant's ID & PK.
+ restaurant1.place_ptr = place3
+ self.assertEqual(restaurant1.pk, place3.pk)
+ self.assertEqual(restaurant1.id, place3.id)
+ self.assertEqual(restaurant1.pk, restaurant1.id)
+ restaurant1.place_ptr = None
+ self.assertIsNone(restaurant1.pk)
+ self.assertIsNone(restaurant1.id)
+ # Changing the parent of an italian restaurant changes the restaurant's
+ # ID & PK.
+ italian_restaurant.restaurant_ptr = restaurant2
+ self.assertEqual(italian_restaurant.pk, restaurant2.pk)
+ self.assertEqual(italian_restaurant.id, restaurant2.id)
+ self.assertEqual(italian_restaurant.pk, italian_restaurant.id)
+ italian_restaurant.restaurant_ptr = None
+ self.assertIsNone(italian_restaurant.pk)
+ self.assertIsNone(italian_restaurant.id)