"on_delete=models.CASCADE" in OneToOne not work as ForeignKey relationship

(Sorry for my bad english) Let’s say I have three models as below:

class Project(models.Model):
...

class Farm(models.Model):
    project = models.OneToOneField("Project", null=True, on_delete=models.CASCADE)

...

class Exporter(models.Model):
    project = models.ForeignKey("Project", on_delete=models.CASCADE)
...


When I delete a Project, I saw that the order of deleted objects is like this:

Exporter → Project → Farm

I think the object which has the foreign key should be deleted first (Exporter and Farm in this case). So, is there anyway to make Farm to be deleted before the deletion of the Project?

I think the object which has the foreign key should be deleted first (Exporter and Farm in this case).

The order of deletion is ambiguous since both deleting Exporter or Farm can be done in any order.

In other world both Exporter and Farm are loose in the dependency graph representing your relationships. When this is the case Django defaults to deleting objects associated with the fields defined first so defining your Exporter model before the Farm one should do.

That’s brittle though so if you want to be more explicit about it you could define your own on_delete handler for Farm that forces the collection of Exporter first as done here.

1 Like

Thank you so much for replying! Let’s me share more about my context.

I’m creating a signal post_delete that logs the deleted objects to console.

For example:

  • Project P has been deleted.
  • Exporter E of Project P has been deleted.
  • Farm F of Project P has been deleted.

When I tried deleting a project, first two logs worked but the third one throwed an exception DoesNotExist, when it tried to access farm.project.name.

After debugging, I think the root cause is because the order of deletion is Exporter → Project → Farm. The Project was deleted before Farm’s deletion so that the Farm cannot access its Project when it was deleted.

Therefore, I expect the order of deletion should be (Exporter, Farm) Project, and I wonder if we have any simple solution to do that. :pensive_face:

Well, did you read the reply above? It contains two solutions, one simple but brittle and a second one more advanced but with stronger guarantees. Not sure what else you are expecting here.

1 Like

It contains two solutions, one simple but brittle and a second one more advanced but with stronger guarantees.

Sorry. I tried the first one. But the Farm still was deleted after the deletion of the Project, so the exception was still thrown.

I’ve just tried remove null=True, and it’s worked! :laughing: So now I think declaring that column as nullable may cause Django to perform deletions in a random order, while not allowing null will ensure that the parent object is always deleted afterward.