2

Is it possible to delete many Model instances without iterating over them and calling .delete() on each one?

Let's say we have something like this:

objects = [o for o in MyObject.objects.filter(...)]

objects_to_delete = get_validate_objects(objects) # some of objects from objects

And now I want to delete every MyObject in objects_to_delete. Is there any better/smarter way than this?:

for o in objects_to_delete:
    o.delete()

Also I want to be sure that all objects were deleted. Exception/message about problem during deleting object (deleted earlier) will be nice.

kedod
  • 121
  • 1
  • 8
  • refer https://stackoverflow.com/questions/9143262/delete-multiple-objects-in-django – N.Moudgil Oct 16 '19 at 11:43
  • You could customize your Manager class, such that `MyObject.valid_objects` already returns a filterset with custom filter semantics, and then just `objects.delete()` them – L3viathan Oct 16 '19 at 11:45
  • I reopened this because the linked question is slightly different and the single answer doesn't answer this. – RemcoGerlich Oct 16 '19 at 11:47
  • Possible duplicate of [Delete multiple objects in django](https://stackoverflow.com/questions/9143262/delete-multiple-objects-in-django) – Kostas Charitidis Oct 16 '19 at 11:52

2 Answers2

4

You can delete a queryset; to get a queryset containing the objects you have in a list you could do:

objects_to_delete = MyObject.objects.filter(pk__in=[o.pk for o in objects])
objects_to_delete.delete()

But ideally you would write "get_validate_objects" in such a way that it took a queryset as parameter and did all its checks on the queryset (using filter() and exclude() and the like). Then you could call .delete() on the result immediately. But that isn't always easy, of course.

RemcoGerlich
  • 30,470
  • 6
  • 61
  • 79
  • I got it. But it not resolved problem where object in `pk__in` was deleted earlier. No message or exception. I can only compare list of deleted ids to numer of deleted objects. – kedod Oct 16 '19 at 12:16
  • @kedod: that's a more fundamental problem, database software does not give you an error if you use a DELETE SQL statement with an IN clause where not all the ids in there match with some row in the table. So you won't get an error from that, it is OK as far as relational databases are concerned. – RemcoGerlich Oct 16 '19 at 12:24
  • 1
    Also, what are you doing that makes it possible they are already deleted, and why does it matter if they are already? – RemcoGerlich Oct 16 '19 at 12:25
2

Since you have objects in objects_to_delete, you can get the ids of those objects and delete. Do something like:

MyObject.objects.filter(id__in=[i.id for i in objects_to_delete]).delete()

It will result in the following SQL.

DELETE FROM MyObject WHERE id IN (ids of objects)

For e.g. if the id's of the objects to be deleted are 1,2, 3, 4, 5 then the sql will be:

DELETE FROM MyObject WHERE id IN (1, 2, 3, 4, 5)
Nalin Dobhal
  • 2,292
  • 2
  • 10
  • 20
  • I got it. But it not resolved problem where object in `pk__in` was deleted earlier. No message or exception. I can only compare list of deleted ids to numer of deleted objects. – kedod Oct 16 '19 at 12:16