Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Possible to do conditional ForeignKey.on_delete in Django?

Tags:

django

Through the on_delete option, Django provides various alternatives for what to do with objects that have a foreign key to an object that is being deleted.

I'm wondering if there is a way I could do something similar, but conditionally. Here's the scenario. I am utilizing Django 1.5's new custom User model and all my users have a ForeignKey to Site. Like so:

class TenantSiteUser(AbstractUser):
  site = models.ForeignKey(Site, null=True)

If a site is deleted, then I'd prefer to delete all the non-superusers linked to that site (i.e., KASKADE-like behavoir), since their existence is now meaningless. But if its a superuser, I'd prefer to just set the user's site to null (i.e., SET_NULL) and let them keep existing, since that's probably me or someone I work with and we tend to not want to unintentionally delete ourselves.

Is there something I can override to manually do a check and implement this type of on_delete behavior?

EDIT: Here's the code that ended up working for me, based on @Kevin's answer and some study of how the existing handlers work:

def NULLIFY_SUPERUSERS_ELSE_CASCADE(collector, field, sub_objs, using):
    superusers = []
    for user in sub_objs:
        if user.is_superuser:
            sub_objs = list(sub_objs)
            sub_objs.remove(user)
            superusers.append(user)

    CASCADE(collector, field, sub_objs, using)
    if len(superusers):
        collector.add_field_update(field, None, superusers)

class TenantSiteUser(AbstractUser):
    site = models.ForeignKey(Site, null=True, on_delete=NULLIFY_SUPERUSERS_ELSE_CASCADE)
like image 458
B Robster Avatar asked Feb 10 '13 02:02

B Robster


1 Answers

The options Django provides (CASCADE, PROTECT etc.) are all functions - here's where they're defined for 1.5.

I haven't tested it, but it should be possible to write your own NULL_OR_CASCADE function and pass that in as your field's on_delete argument.

like image 130
Kevin Avatar answered Oct 24 '22 15:10

Kevin