Fixed #29568 -- Prevented unnecessary UPDATE queries creating child models.
This commit is contained in:
parent
65503ca097
commit
861638a307
|
@ -743,9 +743,13 @@ class Model(metaclass=ModelBase):
|
||||||
update_fields=update_fields,
|
update_fields=update_fields,
|
||||||
)
|
)
|
||||||
with transaction.atomic(using=using, savepoint=False):
|
with transaction.atomic(using=using, savepoint=False):
|
||||||
|
parent_inserted = False
|
||||||
if not raw:
|
if not raw:
|
||||||
self._save_parents(cls, using, update_fields)
|
parent_inserted = self._save_parents(cls, using, update_fields)
|
||||||
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
|
updated = self._save_table(
|
||||||
|
raw, cls, force_insert or parent_inserted,
|
||||||
|
force_update, using, update_fields,
|
||||||
|
)
|
||||||
# Store the database on which the object was saved
|
# Store the database on which the object was saved
|
||||||
self._state.db = using
|
self._state.db = using
|
||||||
# Once saved, this is no longer a to-be-added instance.
|
# Once saved, this is no longer a to-be-added instance.
|
||||||
|
@ -763,13 +767,19 @@ class Model(metaclass=ModelBase):
|
||||||
def _save_parents(self, cls, using, update_fields):
|
def _save_parents(self, cls, using, update_fields):
|
||||||
"""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
|
||||||
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 (field and getattr(self, parent._meta.pk.attname) is None and
|
if (field and getattr(self, parent._meta.pk.attname) is None and
|
||||||
getattr(self, field.attname) is not None):
|
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))
|
||||||
self._save_parents(cls=parent, using=using, update_fields=update_fields)
|
parent_inserted = self._save_parents(cls=parent, using=using, update_fields=update_fields)
|
||||||
self._save_table(cls=parent, using=using, update_fields=update_fields)
|
updated = self._save_table(
|
||||||
|
cls=parent, using=using, update_fields=update_fields,
|
||||||
|
force_insert=parent_inserted,
|
||||||
|
)
|
||||||
|
if not updated:
|
||||||
|
inserted = True
|
||||||
# Set the parent's PK value to self.
|
# Set the parent's PK value to self.
|
||||||
if field:
|
if field:
|
||||||
setattr(self, field.attname, self._get_pk_val(parent._meta))
|
setattr(self, field.attname, self._get_pk_val(parent._meta))
|
||||||
|
@ -780,6 +790,7 @@ class Model(metaclass=ModelBase):
|
||||||
# database if necessary.
|
# database if necessary.
|
||||||
if field.is_cached(self):
|
if field.is_cached(self):
|
||||||
field.delete_cached_value(self)
|
field.delete_cached_value(self)
|
||||||
|
return inserted
|
||||||
|
|
||||||
def _save_table(self, raw=False, cls=None, force_insert=False,
|
def _save_table(self, raw=False, cls=None, force_insert=False,
|
||||||
force_update=False, using=None, update_fields=None):
|
force_update=False, using=None, update_fields=None):
|
||||||
|
|
|
@ -133,6 +133,24 @@ class ModelInheritanceTests(TestCase):
|
||||||
if 'UPDATE' in sql:
|
if 'UPDATE' in sql:
|
||||||
self.assertEqual(expected_sql, sql)
|
self.assertEqual(expected_sql, sql)
|
||||||
|
|
||||||
|
def test_create_child_no_update(self):
|
||||||
|
"""Creating a child with non-abstract parents only issues INSERTs."""
|
||||||
|
def a():
|
||||||
|
GrandChild.objects.create(
|
||||||
|
email='grand_parent@example.com',
|
||||||
|
first_name='grand',
|
||||||
|
last_name='parent',
|
||||||
|
)
|
||||||
|
|
||||||
|
def b():
|
||||||
|
GrandChild().save()
|
||||||
|
for i, test in enumerate([a, b]):
|
||||||
|
with self.subTest(i=i), self.assertNumQueries(4), CaptureQueriesContext(connection) as queries:
|
||||||
|
test()
|
||||||
|
for query in queries:
|
||||||
|
sql = query['sql']
|
||||||
|
self.assertIn('INSERT INTO', sql, sql)
|
||||||
|
|
||||||
def test_eq(self):
|
def test_eq(self):
|
||||||
# Equality doesn't transfer in multitable inheritance.
|
# Equality doesn't transfer in multitable inheritance.
|
||||||
self.assertNotEqual(Place(id=1), Restaurant(id=1))
|
self.assertNotEqual(Place(id=1), Restaurant(id=1))
|
||||||
|
|
Loading…
Reference in New Issue