0

I have a Django model(Feature) sub-classing MPTTModel. As best practice for MPTT model for foreign key is to keep on_delete=PROTECT, struggling to delete all MPTT entries at once, using

        Feature.objects.all().delete()

I get following error

django.db.models.deletion.ProtectedError: ("Cannot delete some instances of model 'Feature' because they are referenced through a protected foreign key: 'Feature.parent'"...

I can either first delete all child nodes, and then root nodes. But this does not seem efficient to me. Is there any better option ?

S.K
  • 480
  • 1
  • 4
  • 19

2 Answers2

0

You should be able to remove all nodes by running a query to get all root nodes and just remove those. I don't know your model structure but something like the following should work:

root_nodes = Feature.objects.filter(parent__isnull=true)
root_nodes.delete()

The docs state that deleting a root-node should work.

Exelian
  • 5,749
  • 1
  • 30
  • 49
0

You can either prune the tree from the leaf nodes with bulk deletes:

from django.db.models import F, Max

max_level = MyModel.objects.all().aggregate(max=Max(F('level')))['max']

while max_level > -1:
    MyModel.objects.filter(level=max_level).delete()
    max_level = max_level - 1

Or you can bypass the Django protection using a single direct SQL command:

from django.db import connection

with connection.cursor() as cursor:
    cursor.execute("DELETE FROM app_mymodel")
regiov
  • 41
  • 2
  • While the direct SQL will work, suggesting that makes me question why the original model has the `PROTECTED` delete attribute to begin with. It sounds like the expected behavior is more akin to `CASCADE`. – gallen Jun 22 '20 at 23:55
  • In my case, because in production mode I want to avoid users deleting nodes with subnodes. However, while the system is still in test, I want an easy way to remove all records from that particular model without having to change its original attributes. But you're right - it should be possible to set CASCADE now and put a note somewhere to remember to switch back to PROTECT before moving to production mode. I just don't like to rely on those notes. – regiov Jun 23 '20 at 14:34