web-dev-qa-db-ja.com

モデルのdelete()をオーバーライドし、関連する削除で引き続き機能させるにはどうすればよいですか

Some_widget_instance.delete()を使用してウィジェットを削除しているため、問題が発生しています。 WidgetFileが削除されたときにハードドライブからファイルを削除できるように、オーバーライドのdelete()メソッドを備えたWidgetFileというモデルもあります。私が抱えている問題は、ウィジェットを削除すると、次のようにWidgetFilesが関連付けられていることです。

class WidgetFile(models.Model):

    widget = models.ForeignKey(Widget)

さて、そのWidgetを削除すると、WidgetFilesは削除されますが、delete()メソッドはトリガーせず、追加のハードドライブの処理を行いません。どんな助けでも大歓迎です。

24
orokusaki

私はそれを考え出した。これをウィジェットモデルに追加しました。

def delete(self):
    files = WidgetFile.objects.filter(widget=self)
    if files:
        for file in files:
            file.delete()
    super(Widget, self).delete()

これにより、関連する各オブジェクトで必要なdelete()メソッドがトリガーされ、カスタムファイル削除コードがトリガーされました。確かにデータベースの方が高価ですが、とにかくハードドライブ上のファイルを削除しようとしている場合、データベースに数回余分にアクセスすることはそれほど大きな費用ではありません。

33
orokusaki

私は同じことをやっていて、Django docsにあるあなたが考えるべきナゲットに気づきました。

事前定義されたモデルメソッドのオーバーライド

DeleteのオーバーライドQuerySetを使用してオブジェクトを一括で削除する場合、オブジェクトのdelete()メソッドは必ずしも呼び出されないことに注意してください。カスタマイズされた削除ロジックが確実に実行されるようにするには、pre_deleteおよび/またはpost_deleteシグナルを使用できます。

これは、スニペットが常に希望どおりに動作しないことを意味します。 Signals の使用は、削除を処理するためのより良いオプションです。

私は次のように行きました:

import shutil
from Django.db.models.signals import pre_delete 
from Django.dispatch import receiver

@receiver(pre_delete)
def delete_repo(sender, instance, **kwargs):
    if sender == Set:
        shutil.rmtree(instance.repo)
67
ElementalVoid

削除する前にclear()を使用すると、関連するオブジェクトセットからすべてのオブジェクトが削除されます。

参照 Django-following-relationships-backward

例:

group.link_set.clear() 
group.delete() 
2
panchicore

これは、1つのウィジェットが1つのWidgetFileに正確に接続されている場合にのみ意味があるようです。その場合は OneToOneField を使用する必要があります

から 1対1の例:

# Delete the restaurant; the waiter should also be removed
>>> r = Restaurant.objects.get(pk=1)
>>> r.delete()
1
vikingosegundo

この問題を回避するために可能な方法でスローするだけです: pre-deletesignal 。 (実際の解決策がないことを決して意味しません。)

1
che

Django サイトで説明されているように見えるはずです:

class Blog(models.Model):
    name = models.CharField(max_length=100)
    tagline = models.TextField()
    def save(self, *args, **kwargs):
        do_something()
        super(Blog, self).save(*args, **kwargs) # Call the "real" save() method.
        do_something_else()

http://docs.djangoproject.com/en/dev/topics/db/models/#overriding-predefined-model-methods

引数を渡すのを忘れた

1

_some_widget_instance_とWidgetまたはWidgetFileのインスタンスはありますか? Widgetのインスタンスの場合、WidgetFileクラスにあるカスタムのdelete()関数を取得できないためです。

0
thornomad

Django 1.9から、単にon_delete=models.CASCADEフィールドの場合、削除時にすべての関連オブジェクトが削除されます。

0
CLTanuki