Django如何在删除模型实例时自动删除AWS S3/DigitalOcean Spaces媒体文件
Django删除模型实例时同步删除S3关联媒体文件的实现方案
Django默认不会在删除模型实例时自动清理关联的FileField文件,你配置了S3/DigitalOcean Spaces存储后端后,只需要触发FileField自带的delete方法,就会自动调用存储后端的API删除远端存储的文件,不需要手动对接对象存储接口。
方法1:重写模型delete方法
直接在你的Note模型中新增delete方法逻辑,单实例删除时会自动触发:
from django.db import models import datetime def directory_path(instance, filename): return 'attachments/{0}_{1}/{2}'.format(instance.date, instance.title, filename) class Note(models.Model): title = models.CharField(max_length=200) date = models.DateField(default=datetime.date.today) attachment = models.FileField(upload_to=directory_path) def __str__(self): return self.title def delete(self, *args, **kwargs): # 先删除关联的存储文件 if self.attachment: # save=False 表示不需要再更新模型字段的值,因为即将删除实例 self.attachment.delete(save=False) # 执行原有的实例删除逻辑 super().delete(*args, **kwargs)
方法2:使用post_delete信号
如果不希望修改模型原生方法,也可以通过Django的信号机制实现,删除实例完成后触发文件清理:
# 可以写在models.py末尾,或者单独创建signals.py后在apps.py中导入 from django.db.models.signals import post_delete from django.dispatch import receiver from django.db import transaction @receiver(post_delete, sender=Note) def delete_note_attachment(sender, instance, **kwargs): if instance.attachment: # 用transaction.on_commit确保实例删除事务提交成功后再删文件,避免事务回滚导致文件误删 transaction.on_commit( lambda: instance.attachment.delete(save=False) )
注意事项
- 以上两种方案仅对单实例删除(即调用
instance.delete())生效,ORM批量删除操作QuerySet.delete()不会触发单个实例的delete方法和post_delete信号。如果需要批量删除时同步清理文件,需要先遍历查询集逐个处理文件再删除实例:notes = Note.objects.filter(xxx) for note in notes: note.attachment.delete(save=False) notes.delete() - 如果需要在更新附件(即替换原有attachment为新文件)时也自动清理旧文件,可以额外添加pre_save信号,对比更新前后的attachment值,删除旧文件。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

