【问题标题】:Overriding Bulk Delete of Models in Django在 Django 中覆盖批量删除模型
【发布时间】:2020-04-23 19:00:10
【问题描述】:

我为模型编写了一个自定义的delete 方法。它似乎有两个注意事项。

  1. 当我进入 Django Admin 中的模型实例并单击删除时,该文件将从 AWS S3 存储桶中删除(这是首先覆盖该方法的目的)。模型本身也会被移除。

  2. 如果我通过“删除所选”批量功能删除,则文件会在 S3 中逗留,但该实例会从该类型的实例列表中删除。

据我了解,在批量删除中,调用了不同的(查询集)方法。

我的问题是,使单次删除和批量删除的行为相同的最有效方法是什么?我应该尝试为此模型创建自定义管理器吗?

模型声明和删除方法:

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)

【问题讨论】:

  • 另外你不需要手动调用 s3 会话(如果你设置了存储后端) Filefield 有删除处理程序( self.videofile.delete() )
  • 它应该按原样工作吗?就我而言,它将文件留在原地。
  • 不,正如我在回答中已经说过的,您必须覆盖或创建自定义操作。我专门评论了使用您编写的 s3 代码,如果您使用适当的存储后端,可以用单行替换(与问题无关,而是与观察相关,所以为什么它是评论)
  • 我该怎么做?我有一个存储后端,但它现在很空旷。

标签: django django-models django-queryset


【解决方案1】:

由于批量删除不使用模型删除方法(docs),您正在做徒劳的工作

请记住,只要有可能,这将纯粹在 SQL,因此各个对象实例的 delete() 方法将 在这个过程中不一定会被调用。如果您提供了 模型类上的自定义 delete() 方法,并希望确保它是 调用,您将需要“手动”删除该模型的实例 (例如,通过遍历 QuerySet 并在每个 单独的对象)而不是使用批量删除()方法 查询集。

Django 管理员删除选定对象不调用模型删除方法(与任何批量删除查询集相同)

From Django admin actions documentation

警告

“删除选定对象”操作使用 QuerySet.delete() 效率原因,其中有一个重要的警告:您的模型的 delete() 方法不会被调用。

如果您希望覆盖此行为,您可以覆盖 ModelAdmin.delete_queryset() 或编写一个自定义操作 以您喜欢的方式删除 - 例如,通过调用 每个选定项目的 Model.delete()。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-07
    相关资源
    最近更新 更多