[解決済み] Django の FileField の削除
質問
DjangoでWebアプリを作っています。私はファイルをアップロードするモデルを持っていますが、私はファイルを削除することはできません。以下は私のコードです。
class Song(models.Model):
name = models.CharField(blank=True, max_length=100)
author = models.ForeignKey(User, to_field='id', related_name="id_user2")
song = models.FileField(upload_to='/songs/')
image = models.ImageField(upload_to='/pictures/', blank=True)
date_upload = models.DateField(auto_now_add=True)
def delete(self, *args, **kwargs):
# You have to prepare what you need before delete the model
storage, path = self.song.storage, self.song.path
# Delete the model before the file
super(Song, self).delete(*args, **kwargs)
# Delete the file after the model
storage.delete(path)
次に
python manage.py shell
こうしています。
song = Song.objects.get(pk=1)
song.delete()
それはデータベースからレコードを削除しますが、サーバー上のファイルは削除されません。 他に何を試すことができますか?
ありがとうございます。
どのように解決するのですか?
Django 1.3 以前では、対応するモデルインスタンスを削除すると、ファイルは自動的にファイルシステムから削除されました。おそらく新しい Django のバージョンを使っているので、自分でファイルシステムからファイルを削除するように実装する必要があります。
シンプルなシグナルベースのサンプル
この記事を書いている時点では、私が選んだ方法は、ミックスされた
post_delete
と
pre_save
シグナルを使用することで、対応するモデルが削除されたり、ファイルが変更されたりするたびに、古いファイルが削除されるようになります。
仮想的な
MediaFile
というモデルを使っています。
import os
import uuid
from django.db import models
from django.dispatch import receiver
from django.utils.translation import ugettext_lazy as _
class MediaFile(models.Model):
file = models.FileField(_("file"),
upload_to=lambda instance, filename: str(uuid.uuid4()))
# These two auto-delete files from filesystem when they are unneeded:
@receiver(models.signals.post_delete, sender=MediaFile)
def auto_delete_file_on_delete(sender, instance, **kwargs):
"""
Deletes file from filesystem
when corresponding `MediaFile` object is deleted.
"""
if instance.file:
if os.path.isfile(instance.file.path):
os.remove(instance.file.path)
@receiver(models.signals.pre_save, sender=MediaFile)
def auto_delete_file_on_change(sender, instance, **kwargs):
"""
Deletes old file from filesystem
when corresponding `MediaFile` object is updated
with new file.
"""
if not instance.pk:
return False
try:
old_file = MediaFile.objects.get(pk=instance.pk).file
except MediaFile.DoesNotExist:
return False
new_file = instance.file
if not old_file == new_file:
if os.path.isfile(old_file.path):
os.remove(old_file.path)
- しばらく前に作ったアプリの1つがこのコードを本番で使ったと思いますが、それでも自己責任で使ってください。
-
例えば
データ損失の可能性
の場合、存在しないファイルを参照してしまう可能性があります。
save()
メソッド呼び出しがたまたまロールバックされるトランザクション内にあった場合、データは存在しないファイルを参照することになるかもしれません。ファイルを削除するロジックをtransaction.on_commit()
にラップすることもできます。transaction.on_commit(lambda: os.remove(old_file.path))
, ミカエルのコメントで提案されているように .django-cleanup
ライブラリ はそのような行を行います . -
エッジケース: アプリが新しいファイルをアップロードし、モデルインスタンスを新しいファイルに指し示すときに、そのファイルに対して
save()
を呼び出さずに (例えばQuerySet
を一括更新するなど)、シグナルが実行されないため、古いファイルが放置されたままになります。これは、従来のファイル処理方法を使用する場合は発生しません。 -
コーディングスタイル: この例では
file
をフィールド名として使っていますが、これは組み込みのfile
オブジェクト識別子と衝突するため、良いスタイルではありません。
補遺: 定期的なクリーンアップ
現実的には、次のようなことが考えられます。 も を定期的に実行し、実行時の失敗でファイルが削除されなかった場合に、孤児ファイルのクリーンアップを処理したいと思うかもしれません。このことを念頭に置いて、おそらくシグナルハンドラを完全に取り除き、そのようなタスクは は タスクは、機密性の低いデータやそれほど大きくないファイルを処理するためのメカニズムです。
しかし、いずれにせよ、もしあなたが は を扱っている場合は、関連する法的責任を回避するために、運用中のデータを適時に削除することを怠らないよう、常に二重、三重にチェックしたほうがよいでしょう。
こちらもご覧ください。
-
FieldFile.delete()
は Django 1.11 のモデルフィールドリファレンスにあります (このリファレンスではFieldFile
クラスを記述していますが.delete()
を直接フィールドで呼び出します。FileField
インスタンスは対応するFieldFile
インスタンスへのプロキシであり、そのメソッドにあたかもフィールドのもののようにアクセスします)モデルが削除されたとき、関連するファイルは削除されないことに注意してください。孤児となったファイルをクリーンアップする必要がある場合は、自分で処理する必要があります (たとえば、手動で実行するか、cron などで定期的に実行するようにスケジュールできるカスタム管理コマンドを使用します)。
-
なぜ Django はファイルを自動的に削除しないのか。 Django 1.3 のリリースノートにあるエントリ
以前のバージョンの Django では、モデルインスタンスに
FileField
が削除されました。FileField
が削除されると、バックエンド ストレージからそのファイルも削除されるように勝手に設定されました。これによって、ロールバックされたトランザクションや、同じファイルを参照する異なるモデルのフィールドなど、いくつかのデータ損失のシナリオへの扉が開かれました。Django 1.3 では、モデルが削除されたときにFileField
'sdelete()
メソッドは呼び出されません。孤児となったファイルのクリーンアップが必要な場合は、自分で処理する必要があります (たとえば、手動で実行したり、cron などで定期的に実行するようスケジュールできるカスタム管理コマンドを使用します)。
関連
-
Django でチェックボックスの値を取得する方法
-
[解決済み] django の OneToOneField と ForeignKey の違いは何ですか?
-
[解決済み] Django のクエリで OR フィルタを行うにはどうすればよいですか?
-
[解決済み】Djangoでnull=Trueとblank=Trueの違いは何ですか?
-
[解決済み] Django のモデルで電話番号を保存する最良の方法は何ですか?
-
[解決済み] Djangoテンプレート内でコレクションのサイズを確認するにはどうすればよいですか?
-
[解決済み] Django は単一のモデルに対してデータをダンプしますか?
-
[解決済み] Djangoです。文字列からモデルを取得する?
-
[解決済み] 学習に適したオープンソースのdjangoプロジェクト【非公開
-
[解決済み] django のモデルのクラス名を取得する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
django store to databaseは現地時間より8時間短い?(2021-05-12更新)
-
[解決済み] Django の管理者パスワードをリセットする方法は?
-
[解決済み] Djangoのテンプレートからsettings.pyの定数にアクセスすることは可能ですか?
-
[解決済み] Djangoテンプレート内でコレクションのサイズを確認するにはどうすればよいですか?
-
[解決済み] DjangoとReactJSを連携させる方法とは?
-
[解決済み] Django テンプレート url タグに url パラメータを追加する方法は?
-
[解決済み] Django が ManyToMany リレーションシップからオブジェクトを取り除く
-
[解決済み] django のクラスベースのビューで permission_required デコレータを使用する方法
-
[解決済み] Django モデルで外部キーフィールドをオプションにすることはできますか?
-
[解決済み] Django 1.9 の apps.py の目的は何ですか?