From 1730c8c7d9c2941b1a6650f21c40d32187e0170c Mon Sep 17 00:00:00 2001
From: Simon Charette <charette.s@gmail.com>
Date: Thu, 28 Feb 2013 18:22:17 -0500
Subject: [PATCH] Fixed #10399 -- Tested that o2o field updates are not
constrained by an inner query.
---
django/test/testcases.py | 36 +++++++++++++++++++++++++++---------
tests/model_inheritance/tests.py | 26 +++++++++++++++++++++++++-
2 files changed, 52 insertions(+), 10 deletions(-)
diff --git a/django/test/testcases.py b/django/test/testcases.py
index f9d028b..208cba0 100644
a
|
b
|
class DocTestRunner(doctest.DocTestRunner):
|
168 | 168 | transaction.rollback_unless_managed(using=conn) |
169 | 169 | |
170 | 170 | |
171 | | class _AssertNumQueriesContext(object): |
172 | | def __init__(self, test_case, num, connection): |
173 | | self.test_case = test_case |
174 | | self.num = num |
| 171 | class CaptureQueriesContext(object): |
| 172 | def __init__(self, connection): |
175 | 173 | self.connection = connection |
176 | 174 | |
| 175 | def __iter__(self): |
| 176 | return iter(self.captured_queries) |
| 177 | |
| 178 | def __getitem__(self, key): |
| 179 | return self.captured_queries[key] |
| 180 | |
| 181 | @property |
| 182 | def captured_queries(self): |
| 183 | return self.connection.queries[self.initial_queries:self.final_queries] |
| 184 | |
177 | 185 | def __enter__(self): |
178 | | self.old_debug_cursor = self.connection.use_debug_cursor |
| 186 | self.use_debug_cursor = self.connection.use_debug_cursor |
179 | 187 | self.connection.use_debug_cursor = True |
180 | | self.starting_queries = len(self.connection.queries) |
| 188 | self.initial_queries = len(self.connection.queries) |
| 189 | self.final_queries = None |
181 | 190 | request_started.disconnect(reset_queries) |
182 | 191 | return self |
183 | 192 | |
184 | 193 | def __exit__(self, exc_type, exc_value, traceback): |
185 | | self.connection.use_debug_cursor = self.old_debug_cursor |
| 194 | self.connection.use_debug_cursor = self.use_debug_cursor |
186 | 195 | request_started.connect(reset_queries) |
187 | 196 | if exc_type is not None: |
188 | 197 | return |
189 | 198 | |
190 | | final_queries = len(self.connection.queries) |
191 | | executed = final_queries - self.starting_queries |
| 199 | self.final_queries = len(self.connection.queries) |
192 | 200 | |
| 201 | |
| 202 | class _AssertNumQueriesContext(CaptureQueriesContext): |
| 203 | def __init__(self, test_case, num, connection): |
| 204 | self.test_case = test_case |
| 205 | self.num = num |
| 206 | super(_AssertNumQueriesContext, self).__init__(connection) |
| 207 | |
| 208 | def __exit__(self, exc_type, exc_value, traceback): |
| 209 | super(_AssertNumQueriesContext, self).__exit__(exc_type, exc_value, traceback) |
| 210 | executed = len(self.captured_queries) |
193 | 211 | self.test_case.assertEqual( |
194 | 212 | executed, self.num, "%d queries executed, %d expected" % ( |
195 | 213 | executed, self.num |
diff --git a/tests/model_inheritance/tests.py b/tests/model_inheritance/tests.py
index 16d2242..46cef3a 100644
a
|
b
|
|
1 | | from __future__ import absolute_import |
| 1 | from __future__ import absolute_import, unicode_literals |
2 | 2 | |
3 | 3 | from operator import attrgetter |
4 | 4 | |
5 | 5 | from django.core.exceptions import FieldError |
| 6 | from django.db import connection |
6 | 7 | from django.test import TestCase |
| 8 | from django.test.testcases import CaptureQueriesContext |
7 | 9 | from django.utils import six |
8 | 10 | |
9 | 11 | from .models import (Chef, CommonInfo, ItalianRestaurant, ParkingLot, Place, |
… |
… |
class ModelInheritanceTests(TestCase):
|
294 | 296 | ) |
295 | 297 | with self.assertNumQueries(6): |
296 | 298 | ir.save() |
| 299 | |
| 300 | def test_update_parent_filtering(self): |
| 301 | """ |
| 302 | Test that updating a field of a model subclass doesn't issue an UPDATE |
| 303 | query constrained by an inner query. |
| 304 | Refs #10399 |
| 305 | """ |
| 306 | supplier = Supplier.objects.create( |
| 307 | name='Central market', |
| 308 | address='610 some street' |
| 309 | ) |
| 310 | # Capture the expected query in a database agnostic way |
| 311 | with CaptureQueriesContext(connection) as captured_queries: |
| 312 | Place.objects.filter(pk=supplier.pk).update(name=supplier.name) |
| 313 | expected_sql = captured_queries[0]['sql'] |
| 314 | # Capture the queries executed when a subclassed model instance is saved. |
| 315 | with CaptureQueriesContext(connection) as captured_queries: |
| 316 | supplier.save(update_fields=('name',)) |
| 317 | for query in captured_queries: |
| 318 | sql = query['sql'] |
| 319 | if 'UPDATE' in sql: |
| 320 | self.assertEqual(expected_sql, sql) |