2012-01-20 15 views
4

私は2つのモデルを持っており、それぞれに画像があります。 1つは、親に外部キーを持っています。親を削除すると、ディスク上のイメージファイルと共に親と子を削除したいと思います。私はdeleteメソッドをオーバーライドすることを行うには:私はMyModelParentのインスタンスを削除親を削除するときに、子モデルの削除メソッドが呼び出されない?

class MyModelParent(models.Model): 
    image = models.ImageField(upload_to = "images/") 

    def delete(self, *args, **kwargs):  
     if self.image: 
      self.image.delete() 
     super(MyModelParent, self).delete(*args, **kwargs) 

class MyModelChild(models.Model): 
    parent = models.ForeignKey(MyModelParent) 
    image = models.ImageField(upload_to = "images/") 

    def delete(self, *args, **kwargs):  
     if self.image: 
      self.image.delete() 
     super(MyModelChild, self).delete(*args, **kwargs) 

、そのオーバーライドされた削除()と呼ばれますが、ない(それらはDBから削除されますが)子供のもの、それらの画像はディスク上に残ります。誰でも私が間違っていることを知っていますか?

答えて

8

あなたは間違ったことはしていません。問題は、子のdelete()メソッドがカスケード時に呼び出されないということです。 deleteのドキュメントから

(データベースクエリを使用していますカスケード削除):

delete()メソッド一括削除しないと(任意の削除を呼び出すことはありません)あなたのモデルに 方法。ただし、削除されたすべてのオブジェクト(カスケードされた の削除を含む)のpre_deleteおよび のpost_deleteシグナルが出力されます。

しかし、pre_deletepost_delete信号がまだ送信されます。必要なのは、これらのシグナルの1つをリッスンし、余分なクリーンアップを行うコールバックを接続することです。 connecting signalsの詳細については、該当するドキュメントを参照してください。

+0

信号を接続するリンクがもう機能していません。 :-( – physicalattraction

2

この動作が原因(デフォルト)ForeignKey's on_deleteキーワード引数の(docに、Making Queries | Deleting objectsから)CASCADEオプションは、単にデータベースの制約を設定しているという事実にある。それを忘れないでください

これは可能な限りSQLで純粋に実行されるため、個々のオブジェクト・インスタンスのdelete()メソッドは必ずしもプロセス中に呼び出されるとは限りません。モデルクラスにカスタムdelete()メソッドを提供し、それが確実に呼び出されるようにするには、そのモデルのインスタンスを手動で削除する必要があります(たとえば、QuerySetを繰り返し、各オブジェクトごとにdelete()を呼び出す) QuerySetのバルクdelete()メソッドを使用するのではなく、

Djangoはオブジェクトを削除すると、デフォルトでSQL制約ON DELETE CASCADEの動作をエミュレートします。つまり、削除対象のオブジェクトを指す外部キーを持つオブジェクトも削除されます。

1

@ネイトの答えは問題の一部をカバーしていますが、低レベルの部分だけをカバーしています。親を削除すると、親に暗黙の外部キーを持つ子もカスケードで削除されますが、このシナリオでは子のdelete()は実行されません。

すべてが正しいですが、それ以上のポイントは、あなたが子供ではなく親を削除しているからです。継承では、親は子の方法について何も知らないので、それが懸念される限り存在しない可能性があるので、無視されます。カスタム子メソッドを実行する場合は、親ではなく子から実行する必要があります。

関連する問題