Search code examples
pythondjangomodelrace-condition

Django: Safely check for related objects before deletion


I have a Django app with two models:

class Foo(models.Model):
    baz = models.CharField(max_length=100)

class Bar(models.Model):
    foo = models.ForeignKey(Foo)

In a view, I want to delete a Bar object. Currently it's done with:

foo_to_delete = Foo.objects.get(pk=1)
if not foo_to_delete.bar_set.exists(): # step 1
    foo_to_delete.delete() # step 2

But now if at the time between the step 1 and the step 2, someone saves a new Bar object with the foo field pointing to foo_to_delete object, this new Bar object would be deleted by step 2.

Is there any way to avoid this, maybe by doing a single SQL call ? Does the Django ORM provides something for doing this kind of check before deletion safely ?


Solution

  • I think I have solved the problem using models.PROTECT.

    The models now looks like this:

    class Foo(models.Model):
        baz = models.CharField(max_length=100)
    
    class Bar(models.Model):
        foo = models.ForeignKey(Foo, on_delete=models.PROTECT)
    

    And the view is like this:

    foo_to_delete = Foo.objects.get(pk=1)
    try:
        foo_to_delete.delete()
    except models.ProtectedError:
        # show an error message
    

    This seems to be mapped to only one SQL query, thus making it safe (I think).