[django] 데이터베이스 / 모델에서 개체를 제거 할 때 Django 관리자가 파일을 삭제하도록하려면 어떻게해야합니까?

표준 ImageField와 함께 1.2.5를 사용하고 내장 스토리지 백엔드를 사용하고 있습니다. 파일은 잘 업로드되지만 관리자에서 항목을 제거하면 서버의 실제 파일이 삭제되지 않습니다.



답변

pre_delete또는 post_delete신호를 수신하고 (아래 @toto_tico의 주석 참조) FileField 객체 에서 delete () 메서드를 호출 할 수 있습니다. 따라서 (models.py에서) :

class MyModel(models.Model):
    file = models.FileField()
    ...

# Receive the pre_delete signal and delete the file associated with the model instance.
from django.db.models.signals import pre_delete
from django.dispatch.dispatcher import receiver

@receiver(pre_delete, sender=MyModel)
def mymodel_delete(sender, instance, **kwargs):
    # Pass false so FileField doesn't save the model.
    instance.file.delete(False)


답변

django-cleanup 시도

pip install django-cleanup

settings.py

INSTALLED_APPS = (
    ...
    'django_cleanup', # should go after your apps
)


답변

Django 1.5 솔루션 : 내 앱 내부의 다양한 이유로 post_delete를 사용합니다.

from django.db.models.signals import post_delete
from django.dispatch import receiver

@receiver(post_delete, sender=Photo)
def photo_post_delete_handler(sender, **kwargs):
    photo = kwargs['instance']
    storage, path = photo.original_image.storage, photo.original_image.path
    storage.delete(path)

나는 이것을 models.py 파일 하단에 붙였다.

original_image필드입니다 ImageField내에서 Photo모델.


답변

이 코드는 관리자 패널에서도 Django 1.4에서 잘 실행됩니다.

class ImageModel(models.Model):
    image = ImageField(...)

    def delete(self, *args, **kwargs):
        # You have to prepare what you need before delete the model
        storage, path = self.image.storage, self.image.path
        # Delete the model before the file
        super(ImageModel, self).delete(*args, **kwargs)
        # Delete the file after the model
        storage.delete(path)

모델을 삭제하기 전에 스토리지와 경로를 가져 오는 것이 중요합니다. 그렇지 않으면 모델이 삭제 된 경우에도 무효가 유지됩니다.


답변

당신은 필요 에 모두 실제 파일을 제거 delete하고 update.

from django.db import models

class MyImageModel(models.Model):
    image = models.ImageField(upload_to='images')

    def remove_on_image_update(self):
        try:
            # is the object in the database yet?
            obj = MyImageModel.objects.get(id=self.id)
        except MyImageModel.DoesNotExist:
            # object is not in db, nothing to worry about
            return
        # is the save due to an update of the actual image file?
        if obj.image and self.image and obj.image != self.image:
            # delete the old image file from the storage in favor of the new file
            obj.image.delete()

    def delete(self, *args, **kwargs):
        # object is being removed from db, remove the file from storage first
        self.image.delete()
        return super(MyImageModel, self).delete(*args, **kwargs)

    def save(self, *args, **kwargs):
        # object is possibly being updated, if so, clean up.
        self.remove_on_image_update()
        return super(MyImageModel, self).save(*args, **kwargs)


답변

pre_delete 또는 post_delete 신호 사용을 고려할 수 있습니다.

https://docs.djangoproject.com/en/dev/topics/signals/

물론 FileField 자동 삭제가 제거 된 동일한 이유가 여기에도 적용됩니다. 다른 곳에서 참조되는 파일을 삭제하면 문제가 발생합니다.

제 경우에는 모든 파일을 관리하는 전용 파일 모델이 있었기 때문에 이것이 적절 해 보였습니다.

참고 : 어떤 이유로 post_delete가 제대로 작동하지 않는 것 같습니다. 파일은 삭제되었지만 데이터베이스 레코드는 그대로 유지되었으므로 오류 조건에서도 예상했던 것과 완전히 반대입니다. pre_delete는 잘 작동합니다.


답변

조금 늦었을지도 모릅니다. 하지만 가장 쉬운 방법은 post_save 신호를 사용하는 것입니다. 신호는 QuerySet 삭제 프로세스 중에도 실행되지만 [model] .delete () 메서드는 QuerySet 삭제 프로세스 중에 실행되지 않으므로이를 재정의하는 가장 좋은 옵션은 아닙니다.

core / models.py :

from django.db import models
from django.db.models.signals import post_delete
from core.signals import delete_image_slide
SLIDE1_IMGS = 'slide1_imgs/'

class Slide1(models.Model):
    title = models.CharField(max_length = 200)
    description = models.CharField(max_length = 200)
    image = models.ImageField(upload_to = SLIDE1_IMGS, null = True, blank = True)
    video_embed = models.TextField(null = True, blank = True)
    enabled = models.BooleanField(default = True)

"""---------------------------- SLIDE 1 -------------------------------------"""
post_delete.connect(delete_image_slide, Slide1)
"""--------------------------------------------------------------------------"""

core / signals.py

import os

def delete_image_slide(sender, **kwargs):
    slide = kwargs.get('instance')
    try:
        os.remove(slide.image.path)
    except:
        pass