Fixed #35073 -- Avoided unnecessary calling of callables used by SET/SET_DEFAULT in Collector.collect().

This commit is contained in:
bcail 2024-02-08 17:41:32 +00:00 committed by GitHub
parent 1b5338d03e
commit 9c5e382b98
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 32 additions and 10 deletions

View File

@ -60,8 +60,9 @@ def SET(value):
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

View File

@ -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"
)

View File

@ -408,9 +408,17 @@ class SetQueryCountTests(TestCase):
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(), [])