Skip to content

Commit c432927

Browse files
czpythontimgraham
authored andcommitted
Fixed #26362 -- Fixed update of the inherited id field of an object when its parent changes.
1 parent fa28306 commit c432927

File tree

2 files changed

+53
-0
lines changed

2 files changed

+53
-0
lines changed

django/db/models/fields/related_descriptors.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,22 @@ def get_object(self, instance):
277277
return obj
278278
return super().get_object(instance)
279279

280+
def __set__(self, instance, value):
281+
super().__set__(instance, value)
282+
# If the primary key is a link to a parent model and a parent instance
283+
# is being set, update the value of the inherited pk(s).
284+
if self.field.primary_key and self.field.remote_field.parent_link:
285+
opts = instance._meta
286+
# Inherited primary key fields from this object's base classes.
287+
inherited_pk_fields = [
288+
field for field in opts.concrete_fields
289+
if field.primary_key and field.remote_field
290+
]
291+
for field in inherited_pk_fields:
292+
rel_model_pk_name = field.remote_field.model._meta.pk.attname
293+
raw_value = getattr(value, rel_model_pk_name) if value is not None else None
294+
setattr(instance, rel_model_pk_name, raw_value)
295+
280296

281297
class ReverseOneToOneDescriptor:
282298
"""

tests/model_inheritance_regress/tests.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -527,3 +527,40 @@ def test_queries_on_parent_access(self):
527527
restaurant = italian_restaurant.restaurant_ptr
528528
self.assertEqual(restaurant.place_ptr.restaurant, restaurant)
529529
self.assertEqual(restaurant.italianrestaurant, italian_restaurant)
530+
531+
def test_id_field_update_on_ancestor_change(self):
532+
place1 = Place.objects.create(name='House of Pasta', address='944 Fullerton')
533+
place2 = Place.objects.create(name='House of Pizza', address='954 Fullerton')
534+
place3 = Place.objects.create(name='Burger house', address='964 Fullerton')
535+
restaurant1 = Restaurant.objects.create(
536+
place_ptr=place1,
537+
serves_hot_dogs=True,
538+
serves_pizza=False,
539+
)
540+
restaurant2 = Restaurant.objects.create(
541+
place_ptr=place2,
542+
serves_hot_dogs=True,
543+
serves_pizza=False,
544+
)
545+
546+
italian_restaurant = ItalianRestaurant.objects.create(
547+
restaurant_ptr=restaurant1,
548+
serves_gnocchi=True,
549+
)
550+
# Changing the parent of a restaurant changes the restaurant's ID & PK.
551+
restaurant1.place_ptr = place3
552+
self.assertEqual(restaurant1.pk, place3.pk)
553+
self.assertEqual(restaurant1.id, place3.id)
554+
self.assertEqual(restaurant1.pk, restaurant1.id)
555+
restaurant1.place_ptr = None
556+
self.assertIsNone(restaurant1.pk)
557+
self.assertIsNone(restaurant1.id)
558+
# Changing the parent of an italian restaurant changes the restaurant's
559+
# ID & PK.
560+
italian_restaurant.restaurant_ptr = restaurant2
561+
self.assertEqual(italian_restaurant.pk, restaurant2.pk)
562+
self.assertEqual(italian_restaurant.id, restaurant2.id)
563+
self.assertEqual(italian_restaurant.pk, italian_restaurant.id)
564+
italian_restaurant.restaurant_ptr = None
565+
self.assertIsNone(italian_restaurant.pk)
566+
self.assertIsNone(italian_restaurant.id)

0 commit comments

Comments
 (0)