91

標準のImageFieldで1.2.5を使用し、組み込みのストレージバックエンドを使用しています。ファイルは正常にアップロードされますが、管理者からエントリを削除しても、サーバー上の実際のファイルは削除されません。

4

13 に答える 13

108

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)
于 2013-01-14T01:11:47.770 に答える
53

django-cleanupをお試しください

pip install django-cleanup

settings.py

INSTALLED_APPS = (
    ...
    'django_cleanup.apps.CleanupConfig',
)
于 2015-03-17T17:21:48.867 に答える
35

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モデルにあります。

于 2013-05-08T14:15:20.037 に答える
18

このコードは、管理パネルを備えたDjango1.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)

モデルを削除する前にストレージとパスを取得することが重要です。そうしないと、モデルを削除しても無効のままになります。

于 2012-07-04T17:28:52.397 に答える
16

との両方で実際のファイルを削除する必要があります。deleteupdate

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)
于 2015-09-18T01:30:06.377 に答える
6

pre_deleteまたはpost_deleteシグナルの使用を検討できます。

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

もちろん、FileFieldの自動削除が削除されたのと同じ理由がここにも当てはまります。他の場所で参照されているファイルを削除すると、問題が発生します。

私の場合、すべてのファイルを管理するための専用のファイルモデルがあったので、これは適切であるように思われました。

注:何らかの理由で、post_deleteが正しく機能していないようです。ファイルは削除されましたが、データベースレコードは残りました。これは、エラー状態でも、私が期待するものとは完全に逆です。ただし、pre_deleteは正常に機能します。

于 2011-11-08T16:50:40.147 に答える
3

多分それは少し遅いです。しかし、私にとって最も簡単な方法は、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 / signal.py

import os

def delete_image_slide(sender, **kwargs):
    slide = kwargs.get('instance')
    try:
        os.remove(slide.image.path)
    except:
        pass
于 2013-08-16T02:26:07.060 に答える
1

この機能はDjango1.3で削除されるので、私はそれに依存しません。

deleteデータベースからエントリを完全に削除する前に、問題のモデルのメソッドをオーバーライドしてファイルを削除できます。

編集:

これが簡単な例です。

class MyModel(models.Model):

    self.somefile = models.FileField(...)

    def delete(self, *args, **kwargs):
        somefile.delete()

        super(MyModel, self).delete(*args, **kwargs)
于 2011-03-21T02:54:51.507 に答える
1

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
于 2014-06-05T23:22:10.773 に答える
0

ファイルの前に必ず「self 」と書いてください。したがって、上記の例は

def delete(self, *args, **kwargs):
        self.somefile.delete()

        super(MyModel, self).delete(*args, **kwargs)

ファイルの前の「自己」を忘れてしまいましたが、グローバル名前空間で検索していたため、機能しませんでした。

于 2013-03-27T17:15:01.897 に答える
0

プロジェクトに未使用のファイルがすでに多数あり、それらを削除したい場合は、djangoユーティリティdjango-unused-mediaを使用できます。

于 2017-01-11T18:50:44.700 に答える
0

Django 2.xソリューション:

パッケージをインストールする必要はありません!Django2では非常に簡単に処理できます。Django 2とSFTPストレージを使用して次のソリューションを試しました(ただし、どのストレージでも機能すると思います)

まず、カスタムマネージャを作成します。したがって、メソッドを使用してモデルのファイルを削除できるようにする場合はobjects、[Custom Manager] [3](のdelete()メソッドをオーバーライドするためobjects)を記述して使用する必要があります。

class CustomManager(models.Manager):
    def delete(self):
        for obj in self.get_queryset():
            obj.delete()

モデル自体を削除する前に削除する必要があります。モデルimageにを割り当てるには、モデル内でCustomManager初期化する必要があります。objects

class MyModel(models.Model):
    image = models.ImageField(upload_to='/pictures/', blank=True)
    objects = CustomManager() # add CustomManager to model
    def delete(self, using=None, keep_parents=False):

    objects = CustomManager() # just add this line of code inside of your model

    def delete(self, using=None, keep_parents=False):
        self.image.storage.delete(self.song.name)
        super().delete()
于 2019-10-25T11:14:07.513 に答える
-1

動的ディレクトリ名を使用してファイルフィールドでupload_toオプションを使用しているため、特殊なケースが発生する可能性がありますが、私が見つけた解決策はos.rmdirを使用することでした。

モデルの場合:

import os

..。

class Some_Model(models.Model):
     save_path = models.CharField(max_length=50)
     ...
     def delete(self, *args,**kwargs):
          os.rmdir(os.path.join(settings.MEDIA_ROOT, self.save_path)
          super(Some_Model,self).delete(*args, **kwargs)
于 2013-02-17T23:01:55.420 に答える