Opened 23 months ago
Closed 21 months ago
#35073 closed Bug (fixed)
models.SET's callable is called when there are no objects to update.
| Reported by: | Fabio Sangiovanni | Owned by: | bcail |
|---|---|---|---|
| Component: | Database layer (models, ORM) | Version: | 4.2 |
| Severity: | Normal | Keywords: | |
| Cc: | Simon Charette, bcail | Triage Stage: | Ready for checkin |
| Has patch: | yes | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | no |
Description
Hello everybody.
With an upgrade from Django 4.1 to 4.2 (but also verified in Django 5.0), I've noticed a change in behavior with how on_delete=models.SET is handled.
Given the following models:
from django.db import models
class Person(models.Model):
name = models.CharField(max_length=32)
def __str__(self):
return self.name
def get_default_person():
return Person.objects.get_or_create(name="ghost")[0]
class Pet(models.Model):
name = models.CharField(max_length=32)
person = models.ForeignKey(Person, related_name="pets", on_delete=models.SET(get_default_person))
def __str__(self):
return self.name
I can see what follows in Django 4.2+ (in ./manage.py shell):
>>> from pets.models import Person, Pet
>>> Person.objects.all()
<QuerySet []>
>>> Pet.objects.all()
<QuerySet []>
>>> Person.objects.create(name="johndoe")
<Person: johndoe>
>>> Person.objects.all()
<QuerySet [<Person: johndoe>]>
>>> Person.objects.all().delete()
(1, {'pets.Person': 1})
>>> Person.objects.all()
<QuerySet [<Person: ghost>]>
What is strange to me is that the "ghost" Person instance is created upon deletion of the "johndoe" instance, even if there are no Pets with a ForeignKey to "johndoe".
Django 4.1 behaves differently (no "ghost" Person is created on deletion of other Person objects).
Is this an intended change? I couldn't find any documentation of this in the release notes.
Thanks so much for your help.
Fabio
Change History (10)
comment:1 by , 23 months ago
| Owner: | changed from to |
|---|---|
| Status: | new → assigned |
comment:2 by , 23 months ago
| Cc: | added |
|---|---|
| Summary: | New behavior of ForeignKey with on_delete=models.SET (Django 4.2 and 5.0) → models.SET's callable is called when there are no objects to update. |
| Type: | Uncategorized → Bug |
comment:3 by , 23 months ago
| Triage Stage: | Unreviewed → Accepted |
|---|
We should fix that.
I think the most straightforward solution is to only set lazy_sub_objs = True on the function returned by SET if the value is not a callable. The same problem exists for SET_DEFAULT when the default is callable.
comment:4 by , 22 months ago
| Cc: | added |
|---|
@O'ktamjon are you still working on this? If not, I can work on it.
comment:5 by , 22 months ago
I opened an in-progress PR with two unit tests, for SET and SET_DEFAULT.
I pinged Simon on the PR, because I haven't figured out how to fix SET_DEFAULT yet.
comment:7 by , 21 months ago
| Patch needs improvement: | set |
|---|
comment:9 by , 21 months ago
| Owner: | changed from to |
|---|---|
| Triage Stage: | Accepted → Ready for checkin |
Thanks for the report. Regression in 0701bb8e1f1771b36cdde45602ad377007e372b3.