0
0
mirror of https://github.com/django/django.git synced 2024-12-01 15:42:04 +01:00

Fixed #29568 -- Prevented unnecessary UPDATE queries creating child models.

This commit is contained in:
François Dupayrat 2018-07-20 14:59:15 +02:00 committed by Tim Graham
parent 65503ca097
commit 861638a307
2 changed files with 33 additions and 4 deletions

View File

@ -743,9 +743,13 @@ class Model(metaclass=ModelBase):
update_fields=update_fields,
)
with transaction.atomic(using=using, savepoint=False):
parent_inserted = False
if not raw:
self._save_parents(cls, using, update_fields)
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
parent_inserted = self._save_parents(cls, 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
self._state.db = using
# 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):
"""Save all the parents of cls using values from self."""
meta = cls._meta
inserted = False
for parent, field in meta.parents.items():
# Make sure the link fields are synced between parent and self.
if (field and getattr(self, parent._meta.pk.attname) is None and
getattr(self, field.attname) is not None):
setattr(self, parent._meta.pk.attname, getattr(self, field.attname))
self._save_parents(cls=parent, using=using, update_fields=update_fields)
self._save_table(cls=parent, using=using, update_fields=update_fields)
parent_inserted = self._save_parents(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.
if field:
setattr(self, field.attname, self._get_pk_val(parent._meta))
@ -780,6 +790,7 @@ class Model(metaclass=ModelBase):
# database if necessary.
if field.is_cached(self):
field.delete_cached_value(self)
return inserted
def _save_table(self, raw=False, cls=None, force_insert=False,
force_update=False, using=None, update_fields=None):

View File

@ -133,6 +133,24 @@ class ModelInheritanceTests(TestCase):
if 'UPDATE' in 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):
# Equality doesn't transfer in multitable inheritance.
self.assertNotEqual(Place(id=1), Restaurant(id=1))