標準の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
Post_deleteを使用するのが正しい方法です。時には物事がうまくいかないことがありますが、ファイルは削除されません。もちろん、post_deleteが使用される前に削除されなかった古いファイルがたくさんある場合があります。オブジェクトが参照するファイルが存在しない場合に基づいてオブジェクトのファイルを削除する関数を作成し、オブジェクトが削除され、ファイルにオブジェクトがない場合は削除します。また、「アクティブ」フラグに基づいて削除することもできますオブジェクト..ほとんどのモデルに追加したもの。チェックするオブジェクト、オブジェクトファイルへのパス、ファイルフィールド、および非アクティブなオブジェクトを削除するためのフラグを渡す必要があります。
def cleanup_model_objects(m_objects, model_path, file_field='image', clear_inactive=False):
# PART 1 ------------------------- INVALID OBJECTS
#Creates photo_file list based on photo path, takes all files there
model_path_list = os.listdir(model_path)
#Gets photo image path for each photo object
model_files = list()
invalid_files = list()
valid_files = list()
for obj in m_objects:
exec("f = ntpath.basename(obj." + file_field + ".path)") # select the appropriate file/image field
model_files.append(f) # Checks for valid and invalid objects (using file path)
if f not in model_path_list:
invalid_files.append(f)
obj.delete()
else:
valid_files.append(f)
print "Total objects", len(model_files)
print "Valid objects:", len(valid_files)
print "Objects without file deleted:", len(invalid_files)
# PART 2 ------------------------- INVALID FILES
print "Files in model file path:", len(model_path_list)
#Checks for valid and invalid files
invalid_files = list()
valid_files = list()
for f in model_path_list:
if f not in model_files:
invalid_files.append(f)
else:
valid_files.append(f)
print "Valid files:", len(valid_files)
print "Files without model object to delete:", len(invalid_files)
for f in invalid_files:
os.unlink(os.path.join(model_path, f))
# PART 3 ------------------------- INACTIVE PHOTOS
if clear_inactive:
#inactive_photos = Photo.objects.filter(active=False)
inactive_objects = m_objects.filter(active=False)
print "Inactive Objects to Delete:", inactive_objects.count()
for obj in inactive_objects:
obj.delete()
print "Done cleaning model."
これは、これを使用する方法です。
photos = Photo.objects.all()
photos_path, tail = ntpath.split(photos[0].image.path) # Gets dir of photos path, this may be different for you
print "Photos -------------->"
cleanup_model_objects(photos, photos_path, file_field='image', clear_inactive=False) # image file is default
この機能はDjango 1.3で削除されるため、これに依存しません。
データベースからエントリを完全に削除する前に、問題のモデルのdelete
メソッドをオーバーライドしてファイルを削除できます。
編集:
以下に簡単な例を示します。
class MyModel(models.Model):
self.somefile = models.FileField(...)
def delete(self, *args, **kwargs):
somefile.delete()
super(MyModel, self).delete(*args, **kwargs)
ファイルの前に「self」と書いてください。したがって、上記の例は
def delete(self, *args, **kwargs):
self.somefile.delete()
super(MyModel, self).delete(*args, **kwargs)
ファイルの前に「自己」を忘れてしまいましたが、それはグローバル名前空間で見ていたので機能しませんでした。
プロジェクトに未使用のファイルがすでにあり、それらを削除する場合は、Django utility Django-unused-media