さて、以下は私が解決した解決策ですが、それは満足のいくものではありません。
すべてのモデルに抽象基本クラスを追加しました。
class MyModel(models.Model):
class Meta:
abstract = True
def pre_delete_handler(self):
pass
シグナルハンドラpre_delete
は、このモデルのサブクラスのイベントをキャッチします。
def pre_delete_handler(sender, instance, **kwargs):
if isinstance(instance, MyModel):
instance.pre_delete_handler()
models.signals.pre_delete.connect(pre_delete_handler)
各モデルで、子レコードが存在する場合ON DELETE RESTRICT
にメソッドから例外をスローすることにより、任意の""関係をシミュレートします。pre_delete_handler
class RelatedRecordsExist(Exception): pass
class SomeModel(MyModel):
...
def pre_delete_handler(self):
if children.count():
raise RelatedRecordsExist("SomeModel has child records!")
これにより、データが変更される前に削除が中止されます。
残念ながら、pre_deleteシグナルのデータを更新することはできません(たとえば、エミュレートするためON DELETE SET NULL
)。削除するオブジェクトのリストは、シグナルが送信される前にDjangoによってすでに生成されているためです。Djangoは、循環参照でスタックすることを回避し、オブジェクトに不必要に複数回シグナリングすることを防ぐためにこれを行います。
削除を確実に実行できるようにするのは、呼び出し元のコードの責任です。これを支援するために、各モデルには、prepare_delete()
キーをNULL
viaself.related_set.clear()
または同様のものに設定する方法があります。
class MyModel(models.Model):
...
def prepare_delete(self):
pass
views.py
myとのコードをあまり変更する必要がないようmodels.py
に、delete()
メソッドはオーバーライドされて次のコマンドMyModel
を呼び出しますprepare_delete()
。
class MyModel(models.Model):
...
def delete(self):
self.prepare_delete()
super(MyModel, self).delete()
これは、明示的にviaobj.delete()
を呼び出した削除は期待どおりに機能することを意味しますが、削除が関連オブジェクトからカスケードされているか、を介して行われqueryset.delete()
、呼び出し元のコードが必要な場所ですべてのリンクが切断されていることを確認していない場合、はpre_delete_handler
例外をスローします。
そして最後にpost_delete_handler
、シグナルで呼び出され、post_delete
モデルが他のデータをクリアできるようにする同様のメソッドをモデルに追加しました(たとえば、ImageField
sのファイルを削除します)。
class MyModel(models.Model):
...
def post_delete_handler(self):
pass
def post_delete_handler(sender, instance, **kwargs):
if isinstance(instance, MyModel):
instance.post_delete_handler()
models.signals.post_delete.connect(post_delete_handler)
それが誰かの助けになり、コードをあまり問題なくより使いやすいものに再スレッド化できることを願っています。
これを改善する方法についての提案は大歓迎です。