1
0
mirror of https://github.com/django/django.git synced 2025-08-10 11:59:13 +00:00

Fixed #33414 -- Fixed creating diamond-shaped MTI objects for common ancestor with primary key that has a default.

Co-authored-by: Simon Charette <charette.s@gmail.com>
This commit is contained in:
Akash Kumar Sen 2023-05-30 20:08:43 +05:30 committed by Mariusz Felisiak
parent 1c4f5f314e
commit 5d20e02078
3 changed files with 49 additions and 11 deletions

View File

@ -900,10 +900,12 @@ class Model(AltersData, metaclass=ModelBase):
save_base.alters_data = True save_base.alters_data = True
def _save_parents(self, cls, using, update_fields): def _save_parents(self, cls, using, update_fields, updated_parents=None):
"""Save all the parents of cls using values from self.""" """Save all the parents of cls using values from self."""
meta = cls._meta meta = cls._meta
inserted = False inserted = False
if updated_parents is None:
updated_parents = {}
for parent, field in meta.parents.items(): for parent, field in meta.parents.items():
# Make sure the link fields are synced between parent and self. # Make sure the link fields are synced between parent and self.
if ( if (
@ -912,16 +914,23 @@ class Model(AltersData, metaclass=ModelBase):
and getattr(self, field.attname) is not None and getattr(self, field.attname) is not None
): ):
setattr(self, parent._meta.pk.attname, getattr(self, field.attname)) setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
parent_inserted = self._save_parents( if (parent_updated := updated_parents.get(parent)) is None:
cls=parent, using=using, update_fields=update_fields parent_inserted = self._save_parents(
) cls=parent,
updated = self._save_table( using=using,
cls=parent, update_fields=update_fields,
using=using, updated_parents=updated_parents,
update_fields=update_fields, )
force_insert=parent_inserted, updated = self._save_table(
) cls=parent,
if not updated: using=using,
update_fields=update_fields,
force_insert=parent_inserted,
)
if not updated:
inserted = True
updated_parents[parent] = updated
elif not parent_updated:
inserted = True inserted = True
# Set the parent's PK value to self. # Set the parent's PK value to self.
if field: if field:

View File

@ -186,3 +186,23 @@ class Child(Parent):
class GrandChild(Child): class GrandChild(Child):
pass pass
class CommonAncestor(models.Model):
id = models.IntegerField(primary_key=True, default=1)
class FirstParent(CommonAncestor):
first_ancestor = models.OneToOneField(
CommonAncestor, models.CASCADE, primary_key=True, parent_link=True
)
class SecondParent(CommonAncestor):
second_ancestor = models.OneToOneField(
CommonAncestor, models.CASCADE, primary_key=True, parent_link=True
)
class CommonChild(FirstParent, SecondParent):
pass

View File

@ -9,6 +9,7 @@ from django.test.utils import CaptureQueriesContext, isolate_apps
from .models import ( from .models import (
Base, Base,
Chef, Chef,
CommonChild,
CommonInfo, CommonInfo,
CustomSupplier, CustomSupplier,
GrandChild, GrandChild,
@ -149,6 +150,14 @@ class ModelInheritanceTests(TestCase):
# accidentally found). # accidentally found).
self.assertSequenceEqual(s.titles.all(), []) self.assertSequenceEqual(s.titles.all(), [])
def test_create_diamond_mti_default_pk(self):
# 1 INSERT for each base.
with self.assertNumQueries(4):
common_child = CommonChild.objects.create()
# 3 SELECTs for the parents, 1 UPDATE for the child.
with self.assertNumQueries(4):
common_child.save()
def test_update_parent_filtering(self): def test_update_parent_filtering(self):
""" """
Updating a field of a model subclass doesn't issue an UPDATE Updating a field of a model subclass doesn't issue an UPDATE