Is there a simple way, using on_delete, to delete the object containing a ForeignKey when that ForeignKey is deleted (like models.CASCADE would normally do) but just the ForeignKey relationship to None if some condition is met (like models.SET_NULL would normally do).
Here is some code:
class SomeThing(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
related_name="things",
on_delete=models.CONDITIONAL_CASCADE, # obviously this is wrong
)
is_private = models.BooleanField(default=False)
>>> user = User(username="bob").save()
>>> public_thing = SomeThing(is_private=False)
>>> private_thing = SomeThing(is_private=True)
>>> user.things.add(public_thing)
>>> user.things.add(private_thing)
>>> user.delete()
When user is deleted I would like private_thing to be deleted along w/ user, but public_thing to not be deleted and for public_thing.user to be set to None.
Thanks.
edit:
Thanks to @Jarad's suggestion, I wound up writing the following generic function:
def CONDITIONAL_CASCADE(collector, field, sub_objs, using, **kwargs):
condition = kwargs.get("condition", {})
default_value = kwargs.get("default_value", None)
sub_objs_to_cascade = sub_objs.filter(**condition)
sub_objs_to_set = sub_objs.exclude(**condition)
models.CASCADE(collector, field, sub_objs_to_cascade, using)
collector.add_field_update(field, default_value, sub_objs_to_set)
and using it like this:
CASCADE_PRIVATE_THINGS_ONLY = partial(
CONDITIONAL_CASCADE,
condition={"is_private": True},
default_value=None
)