summaryrefslogtreecommitdiff
path: root/tests/delete_regress
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2022-08-17 16:33:22 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-08-27 14:25:55 +0200
commit0701bb8e1f1771b36cdde45602ad377007e372b3 (patch)
treed8f47ccb93c1153a31d62a85e6e82a09be66ef90 /tests/delete_regress
parenta9be1dc5515e99ed96a2c640f5495af419c85b93 (diff)
downloaddjango-0701bb8e1f1771b36cdde45602ad377007e372b3.tar.gz
Fixed #33928 -- Avoided unnecessary queries when cascade updating.
Models that use SET, SET_NULL, and SET_DEFAULT as on_delete handler don't have to fetch objects for the sole purpose of passing them back to a follow up UPDATE query filtered by the retrieved objects primary key. This was achieved by flagging SET handlers as _lazy_ and having the collector logic defer object collections until the last minute. This should ensure that the rare cases where custom on_delete handlers are defined remain uncalled when when dealing with an empty collection of instances. This reduces the number queries required to apply SET handlers from 2 to 1 where the remaining UPDATE use the same predicate as the non removed SELECT query. In a lot of ways this is similar to the fast-delete optimization that was added in #18676 but for updates this time. The conditions only happen to be simpler in this case because SET handlers are always terminal. They never cascade to more deletes that can be combined. Thanks Renan GEHAN for the report.
Diffstat (limited to 'tests/delete_regress')
-rw-r--r--tests/delete_regress/models.py6
-rw-r--r--tests/delete_regress/tests.py16
2 files changed, 22 insertions, 0 deletions
diff --git a/tests/delete_regress/models.py b/tests/delete_regress/models.py
index dc8658e6c4..cbe6fef334 100644
--- a/tests/delete_regress/models.py
+++ b/tests/delete_regress/models.py
@@ -90,6 +90,12 @@ class Location(models.Model):
class Item(models.Model):
version = models.ForeignKey(Version, models.CASCADE)
location = models.ForeignKey(Location, models.SET_NULL, blank=True, null=True)
+ location_value = models.ForeignKey(
+ Location, models.SET(42), default=1, db_constraint=False, related_name="+"
+ )
+ location_default = models.ForeignKey(
+ Location, models.SET_DEFAULT, default=1, db_constraint=False, related_name="+"
+ )
# Models for #16128
diff --git a/tests/delete_regress/tests.py b/tests/delete_regress/tests.py
index c9d0ff8d0a..7dccbf555d 100644
--- a/tests/delete_regress/tests.py
+++ b/tests/delete_regress/tests.py
@@ -399,3 +399,19 @@ class DeleteDistinct(SimpleTestCase):
Book.objects.distinct().delete()
with self.assertRaisesMessage(TypeError, msg):
Book.objects.distinct("id").delete()
+
+
+class SetQueryCountTests(TestCase):
+ def test_set_querycount(self):
+ policy = Policy.objects.create()
+ version = Version.objects.create(policy=policy)
+ location = Location.objects.create(version=version)
+ Item.objects.create(
+ version=version,
+ location=location,
+ location_default=location,
+ location_value=location,
+ )
+ # 3 UPDATEs for SET of item values and one for DELETE locations.
+ with self.assertNumQueries(4):
+ location.delete()