From d5c7f9efc3702888b556cbf932116421b464e8b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anssi=20K=C3=A4=C3=A4ri=C3=A4inen?= Date: Sat, 12 May 2012 13:01:45 +0300 Subject: [PATCH] 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. --- django/db/models/sql/compiler.py | 6 ++++++ tests/modeltests/model_inheritance/tests.py | 18 ++++++++++++++++++ tests/modeltests/update_only_fields/tests.py | 5 +---- 3 files changed, 25 insertions(+), 4 deletions(-) diff --git a/django/db/models/sql/compiler.py b/django/db/models/sql/compiler.py index 3cd26d3bc9..36d45b7cb6 100644 --- a/django/db/models/sql/compiler.py +++ b/django/db/models/sql/compiler.py @@ -1015,6 +1015,12 @@ class SQLUpdateCompiler(SQLCompiler): query.extra = {} query.select = [] 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 # Now we adjust the current query: reset the where clause and get rid diff --git a/tests/modeltests/model_inheritance/tests.py b/tests/modeltests/model_inheritance/tests.py index 2e1a7a5a9c..695d3f836c 100644 --- a/tests/modeltests/model_inheritance/tests.py +++ b/tests/modeltests/model_inheritance/tests.py @@ -275,3 +275,21 @@ class ModelInheritanceTests(TestCase): def test_mixin_init(self): m = MixinModel() 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() diff --git a/tests/modeltests/update_only_fields/tests.py b/tests/modeltests/update_only_fields/tests.py index 8609821a44..e843bd7ab9 100644 --- a/tests/modeltests/update_only_fields/tests.py +++ b/tests/modeltests/update_only_fields/tests.py @@ -1,6 +1,6 @@ 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 .models import Person, Employee, ProxyEmployee, Profile, Account @@ -123,9 +123,6 @@ class UpdateOnlyFieldsTests(TestCase): self.assertEqual(len(pre_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): s = Employee.objects.create(name='Sara', gender='F') s.employee_num = 1