简体   繁体   English

Django - 从亚马逊 S3 中删除文件

[英]Django - Delete file from amazon S3

I have a problem where deleting an object form the admin won't delete the file associated with it.我有一个问题,即从管理员中删除一个对象不会删除与之关联的文件。 after some research I decided to implement a post_delete in the model.经过一番研究,我决定在模型中实现 post_delete。 For some reason I am not able to make the s3 delete the file, even after searching numerous guides and snippets, maybe someone here knows.出于某种原因,即使在搜索了大量指南和片段之后,我也无法让 s3 删除文件,也许这里有人知道。 I use django 1.5 and boto.我使用 django 1.5 和 boto。 Heres my code for the model:这是我的模型代码:

from django.db import models
from django.contrib.auth.models import User
from fileservice.formatChecker import ContentTypeRestrictedFileField
from south.modelsinspector import add_introspection_rules
import os
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
from django.core.files.storage import default_storage as storage
add_introspection_rules([
    (
        [ContentTypeRestrictedFileField], # Class(es) these apply to
        [],         # Positional arguments (not used)
        {           # Keyword argument
            "content_types": ["content_types", {}],
            "max_upload_size": ["max_upload_size", {}]
        },
    ),
], ["^fileservice\.formatChecker\.ContentTypeRestrictedFileField"])

class Contentfile(models.Model):
    content = ContentTypeRestrictedFileField(upload_to='uploads/', content_types=['video/mp4', 'application/pdf', 'image/gif', 'image/jpeg', 'image/png'],max_upload_size=5242880,blank=True, null=True, help_text='Upload a file to add it to the content the app displayes')
    created_at = models.DateTimeField(auto_now_add=True, editable=False)
    updated_at = models.DateTimeField(auto_now=True, editable=False)
    title = models.CharField(max_length=255, unique=True)
    file_type = models.CharField(max_length=5)
    published = models.BooleanField(default=True)
    file_owner = models.ForeignKey(User, related_name='Contentfiles')

    class Meta:
        ordering = ["title"]

    def __unicode__(self):
        return self.title

    def save(self, *args, **kwargs):
        file_name = os.path.basename(self.content.name)
        self.file_type = file_name.split('.')[-1]
        self.title = file_name.split('.')[0]
        self.published = True
        super(Contentfile, self).save(*args, **kwargs)



@receiver(models.signals.post_delete, sender=Contentfile)
def auto_delete_file_on_delete(sender, instance, **kwargs):
    """Deletes file from filesystem
    when corresponding `MediaFile` object is deleted.
    """
    if instance.content:
        if os.path.isfile(storage.open(instance.content.path)):
            os.remove(storage.open(instance.content.path))

@receiver(models.signals.pre_save, sender=Contentfile)
def auto_delete_file_on_change(sender, instance, **kwargs):
    """Deletes file from filesystem
    when corresponding `MediaFile` object is changed.
    """
    if not instance.pk:
        return False

    try:
        old_file = Contentfile.objects.get(pk=instance.pk).content
    except Conentfile.DoesNotExist:
        return False

    new_file = instance.content
    if not old_file == new_file:
        if os.path.isfile(storage.open(old_file.path)):
            os.remove(storage.open(old_file.path))

It is MUCH safer to do post_delete.执行 post_delete 更安全。 If something goes wrong you will start missing S3 files and you wont notice it because your DB records are intact.如果出现问题,您将开始丢失 S3 文件并且您不会注意到它,因为您的数据库记录完好无损。 post_delete will be safer since it is less likely that S3 delete operation would fail after you have deleted your db record. post_delete 会更安全,因为在删除数据库记录后 S3 删除操作失败的可能性较小。 Furthermore even if file delete fails you will be left with a bunch of unreferenced S3 file which are harmless and can be easily cleaned up.此外,即使文件删除失败,您也会留下一堆未引用的 S3 文件,这些文件是无害的,可以轻松清理。

@receiver(models.signals.post_delete, sender=Picture)
def remove_file_from_s3(sender, instance, using, **kwargs):
    instance.img.delete(save=False)

You need to call FieldFile's delete() method to remove the file in S3.您需要调用FieldFile 的delete()方法来删除 S3 中的文件。 In your case, add a pre_delete signal where you call it:在您的情况下,在您调用它的地方添加一个pre_delete信号:

@receiver(models.signals.pre_delete, sender=ContentFile)
def remove_file_from_s3(sender, instance, using):
    instance.content.delete(save=False)

尝试django-cleanup ,它会在您删除模型时自动调用 FileField 上的 delete 方法。

This worked for me by deleting files both in DB and in AWS S3.通过删除数据库和 AWS S3 中的文件,这对我有用。

from django.db import models
from django.dispatch import receiver
from django.views import generic
from project.models import ContentFile
from django.contrib.auth.mixins import LoginRequiredMixin,UserPassesTestMixin

class DeleteFileView(LoginRequiredMixin,UserPassesTestMixin,generic.DeleteView):
   model = ContentFile
   template_name = 'file-delete.html'
   success_url = 'redirect-to'

   #Check if the owner of the file is the one trying to delete a file
   def test_func(self):
      obj = self.get_object()
      if obj.user == self.request.user:
        return True
      return False

    #This code does magic for S3 file deletion 
    @receiver(models.signals.pre_delete, sender=ContentFile)
    def remove_file_from_s3(sender, instance, using, **kwargs):
       instance.image_file.delete(save=False)

I am using pre_delete you can check the django documentation .File reference deletion in DB is done by DeleteView, I hope this helps someone我正在使用pre_delete你可以查看django 文档。DB 中的 文件引用删除是由 DeleteView 完成的,我希望这对某人有所帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM