MadPhysicist
MadPhysicist

Reputation: 5831

Overriding Bulk Delete of Models in Django

I wrote a custom delete method for a model. It appears to work with two caveats.

  1. When I enter into the model instance inside the Django Admin and click delete, then the file is deleted from AWS S3 bucket (that was the purpose of overriding the method in the first place). The model itself gets removed as well.

  2. If I delete via "Delete Selected" bulk feature, then the file lingers in S3, but the instance gets removed from the list of instances of this type.

It is my understanding that in the bulk delete, a different (queryset) method is invoked.

My question is what is the most effective method of making both single and bulk deletes act the same? Should I be trying to create a custom manager for this model?

The model declaration and delete method:

from boto3.session import Session
from django.conf import settings

class Video(models.Model):
    title=models.CharField(max_length=500)
    description=models.TextField(default="")
    creation_date=models.DateTimeField(default=timezone.now)
    videofile=models.FileField(upload_to='videos/', null=True, verbose_name="")
    tags = TaggableManager()

    actions = ['delete']

    def __str__(self):
        return self.title + ": " + str(self.videofile)

    def delete(self, *args, **kwargs):
        session = Session (settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
        s3_resource = session.resource('s3')
        s3_bucket = s3_resource.Bucket(settings.AWS_STORAGE_BUCKET_NAME)

        file_path = "media/" + str(self.videofile)
        response = s3_bucket.delete_objects(
            Delete={
                'Objects': [
                    {
                        'Key': file_path
                    }
                ]
            })
        print(file_path)
        print(response)
        super(Video, self).delete(*args, **kwargs)

Upvotes: 1

Views: 1468

Answers (1)

iklinac
iklinac

Reputation: 15738

You are doing futile work as bulk delete does not use Model delete method ( docs )

Keep in mind that this will, whenever possible, be executed purely in SQL, and so the delete() methods of individual object instances will not necessarily be called during the process. If you’ve provided a custom delete() method on a model class and want to ensure that it is called, you will need to “manually” delete instances of that model (e.g., by iterating over a QuerySet and calling delete() on each object individually) rather than using the bulk delete() method of a QuerySet.

Django Admin delete selected objects does not call Models delete method ( same as any bulk delete queryset)

From Django admin actions documentation

Warning

The “delete selected objects” action uses QuerySet.delete() for efficiency reasons, which has an important caveat: your model’s delete() method will not be called.

If you wish to override this behavior, you can override ModelAdmin.delete_queryset() or write a custom action which does deletion in your preferred manner – for example, by calling Model.delete() for each of the selected items.

Upvotes: 2

Related Questions