From d5c7f9efc3702888b556cbf932116421b464e8b8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Anssi=20K=C3=A4=C3=A4ri=C3=A4inen?= <akaariai@gmail.com>
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