I have a Django model:
class Event(models.Model):
fk = models.ForeignKey(Foreign, null=True, on_delete=models.SET_NULL)
display = display = models.BooleanField(default=True)
...
I'd like to override the save method to turn off display for other events that share the fk value. However, I keep reaching infinite recursion loops because if I override the save method and then save the other objects, it keeps calling the function. Is there a way to only run the save method on the first object that's saved and not keep creating recursive instances?
CodePudding user response:
You can work .update(…)
[Django-doc] a QuerySet
of other objects, with:
from django.db.models import Q
class Event(models.Model):
fk = models.ForeignKey(Foreign, null=True, on_delete=models.SET_NULL)
display = models.BooleanField(default=True)
# …
def save(self, *args, **kwargs):
if self.fk_id is not None and self.display:
Event.objects.filter(
~Q(pk=self.pk), fk_id=self.fk_id
).update(display=False)
return super().save(*args, **kwargs)
But this also immediately shows that there are ways to circumvent the .save(…)
method [Django-doc] on a model, therefore just overriding .save(…)
will not be sufficient, since there are ORM methods that circumvent the .save(…)
and pre-save and post-save signals (which are triggered by the the .save(…)
method).
You can also add a constraint to enforce that there is at most one Event
for each fk
that has display=True
:
from django.db.models import Q
class Event(models.Model):
fk = models.ForeignKey(Foreign, null=True, on_delete=models.SET_NULL)
display = models.BooleanField(default=True)
# …
class Meta:
constraints = [
models.UniqueConstraint(
fields=('fk',),
condition=Q(display=True),
name='only_one_display_per_fk'
)
]