From 9c5e382b981608a26f2c55f1259d9e823fee5f15 Mon Sep 17 00:00:00 2001 From: bcail Date: Thu, 8 Feb 2024 17:41:32 +0000 Subject: [PATCH] Fixed #35073 -- Avoided unnecessary calling of callables used by SET/SET_DEFAULT in Collector.collect(). --- django/db/models/deletion.py | 6 ++---- tests/delete_regress/models.py | 22 +++++++++++++++++++--- tests/delete_regress/tests.py | 14 +++++++++++--- 3 files changed, 32 insertions(+), 10 deletions(-) diff --git a/django/db/models/deletion.py b/django/db/models/deletion.py index bc26d82e934c..022dec940b60 100644 --- a/django/db/models/deletion.py +++ b/django/db/models/deletion.py @@ -60,8 +60,9 @@ def set_on_delete(collector, field, sub_objs, using): def set_on_delete(collector, field, sub_objs, using): collector.add_field_update(field, value, sub_objs) + set_on_delete.lazy_sub_objs = True + set_on_delete.deconstruct = lambda: ("django.db.models.SET", (value,), {}) - set_on_delete.lazy_sub_objs = True return set_on_delete @@ -76,9 +77,6 @@ def SET_DEFAULT(collector, field, sub_objs, using): collector.add_field_update(field, field.get_default(), sub_objs) -SET_DEFAULT.lazy_sub_objs = True - - def DO_NOTHING(collector, field, sub_objs, using): pass diff --git a/tests/delete_regress/models.py b/tests/delete_regress/models.py index cbe6fef33434..4bc035e1c7df 100644 --- a/tests/delete_regress/models.py +++ b/tests/delete_regress/models.py @@ -93,9 +93,6 @@ class Item(models.Model): 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 @@ -151,3 +148,22 @@ class OrderedPerson(models.Model): class Meta: ordering = ["name"] + + +def get_best_toy(): + toy, _ = Toy.objects.get_or_create(name="best") + return toy + + +def get_worst_toy(): + toy, _ = Toy.objects.get_or_create(name="worst") + return toy + + +class Collector(models.Model): + best_toy = models.ForeignKey( + Toy, default=get_best_toy, on_delete=models.SET_DEFAULT, related_name="toys" + ) + worst_toy = models.ForeignKey( + Toy, models.SET(get_worst_toy), related_name="bad_toys" + ) diff --git a/tests/delete_regress/tests.py b/tests/delete_regress/tests.py index 89f4d5ddd89a..ce5a0db8ab86 100644 --- a/tests/delete_regress/tests.py +++ b/tests/delete_regress/tests.py @@ -408,9 +408,17 @@ def test_set_querycount(self): 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): + # 2 UPDATEs for SET of item values and one for DELETE locations. + with self.assertNumQueries(3): location.delete() + + +class SetCallableCollectorDefaultTests(TestCase): + def test_set(self): + # Collector doesn't call callables used by models.SET and + # models.SET_DEFAULT if not necessary. + Toy.objects.create(name="test") + Toy.objects.all().delete() + self.assertSequenceEqual(Toy.objects.all(), [])