Fixed #18304 -- Optimized save() when update_can_self_select=False

Databases with update_can_self_select = False (MySQL for example)
generated non-necessary queries when saving a multitable inherited
model, and when the save resulted in update.
This commit is contained in:
Anssi Kääriäinen 2012-05-12 13:01:45 +03:00
parent 6219591f2e
commit d5c7f9efc3
3 changed files with 25 additions and 4 deletions

View File

@ -1015,6 +1015,12 @@ class SQLUpdateCompiler(SQLCompiler):
query.extra = {} query.extra = {}
query.select = [] query.select = []
query.add_fields([query.model._meta.pk.name]) query.add_fields([query.model._meta.pk.name])
# Recheck the count - it is possible that fiddling with the select
# fields above removes tables from the query. Refs #18304.
count = query.count_active_tables()
if not self.query.related_updates and count == 1:
return
must_pre_select = count > 1 and not self.connection.features.update_can_self_select must_pre_select = count > 1 and not self.connection.features.update_can_self_select
# Now we adjust the current query: reset the where clause and get rid # Now we adjust the current query: reset the where clause and get rid

View File

@ -275,3 +275,21 @@ class ModelInheritanceTests(TestCase):
def test_mixin_init(self): def test_mixin_init(self):
m = MixinModel() m = MixinModel()
self.assertEqual(m.other_attr, 1) self.assertEqual(m.other_attr, 1)
def test_update_query_counts(self):
"""
Test that update queries do not generate non-necessary queries.
Refs #18304.
"""
c = Chef.objects.create(name="Albert")
ir = ItalianRestaurant.objects.create(
name="Ristorante Miron",
address="1234 W. Ash",
serves_hot_dogs=False,
serves_pizza=False,
serves_gnocchi=True,
rating=4,
chef=c
)
with self.assertNumQueries(6):
ir.save()

View File

@ -1,6 +1,6 @@
from __future__ import absolute_import from __future__ import absolute_import
from django.test import TestCase, skipUnlessDBFeature from django.test import TestCase
from django.db.models.signals import pre_save, post_save from django.db.models.signals import pre_save, post_save
from .models import Person, Employee, ProxyEmployee, Profile, Account from .models import Person, Employee, ProxyEmployee, Profile, Account
@ -123,9 +123,6 @@ class UpdateOnlyFieldsTests(TestCase):
self.assertEqual(len(pre_save_data), 0) self.assertEqual(len(pre_save_data), 0)
self.assertEqual(len(post_save_data), 0) self.assertEqual(len(post_save_data), 0)
# A bug in SQLUpdateCompiler prevents this test from succeeding on MySQL
# Require update_can_self_select for this test for now. Refs #18304.
@skipUnlessDBFeature('update_can_self_select')
def test_num_queries_inheritance(self): def test_num_queries_inheritance(self):
s = Employee.objects.create(name='Sara', gender='F') s = Employee.objects.create(name='Sara', gender='F')
s.employee_num = 1 s.employee_num = 1