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:
parent
1c4f5f314e
commit
5d20e02078
@ -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:
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user