web-dev-qa-db-ja.com

Djangoシグナルと上書き保存メソッド

これに頭を巻きつけるのに苦労しています。現在、次のようなモデルがいくつかあります。

 def Review(models.Model)
    ...fields...
    overall_score = models.FloatField(blank=True)

def Score(models.Model)
    review = models.ForeignKey(Review)
    question = models.TextField()
    grade = models.IntegerField()

レビューにはいくつかの「スコア」があり、overall_scoreはスコアの平均です。レビューまたはスコアが保存されると、overall_score平均を再計算する必要があります。現在、上書きされた保存メソッドを使用しています。 Djangoのシグナルディスパッチャーを使用するメリットはありますか?

85
imjoevasquez

信号の保存/削除は、問題のモデルに完全に固有ではない変更を行う必要がある場合や、共通点があるモデルに適用したり、モデル全体で使用するように構成したりできる場合に一般的に適しています。

オーバーライドされたsaveメソッドの一般的なタスクの1つは、モデル内のテキストフィールドからのスラッグの自動生成です。これは、いくつかのモデルに実装する必要がある場合にpre_save信号を使用することでメリットが得られる例です。この場合、シグナルハンドラーはスラグフィールドの名前とフィールドの名前を取得できます。スラッグを生成します。このようなものを配置すると、配置した拡張機能はすべてのモデルに適用されます。一意性を確保するために、問題のモデルのタイプに追加しようとしているスラッグを検索します。

再利用可能なアプリケーションは、多くの場合、信号を使用することでメリットを得ます。アプリケーションが提供する機能を任意のモデルに適用できる場合、一般に(不可避でない限り)ユーザーはモデルから直接メリットを得る必要があります。

たとえば Django-mptt の場合、pre_save信号を使用して、作成または更新されようとしているモデルのツリー構造とpre_deleteシグナルは、削除されるオブジェクトとそのオブジェクトが削除される前に、オブジェクトのサブツリー全体のツリー構造の詳細を削除します。シグナルを使用するため、ユーザーはモデルのsaveまたはdeleteメソッドを追加または変更してこの管理を行う必要がなく、Django-mpttに通知するだけで済みます。管理したいモデル。

81
Jonny Buchanan

あなたは尋ねました:

Djangoのシグナルディスパッチャーを使用するメリットはありますか?

私はDjango docsでこれを見つけました:

オーバーライドされたモデルメソッドは一括操作では呼び出されません

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

残念ながら、save()、pre_save、post_saveのいずれも呼び出されないため、オブジェクトを一括で作成または更新する場合の回避策はありません。

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

18
guettli

シグナルを使用する場合は、関連するスコアモデルが保存されるたびにレビュースコアを更新できます。しかし、そのような機能が必要ない場合は、これをシグナル化する理由はありません。これは、モデルに関連したものです。

3

それは一種の非正規化です。これを見てください かなりの解決策 。インプレース構成フィールドの定義。

2
Alex Koshelev

Djangoからの小さな追加一括削除に関するドキュメント(QuerySetオブジェクトの.delete()メソッド):

これは可能な限り純粋にSQLで実行されるため、個々のオブジェクトインスタンスのdelete()メソッドがプロセス中に呼び出されるとは限らないことに注意してください。モデルクラスにカスタムのdelete()メソッドを提供し、それが呼び出されるようにしたい場合は、そのモデルのインスタンスを「手動で」削除する必要があります(たとえば、QuerySetを反復してdelete()を呼び出すことにより、各オブジェクトを個別に)QuerySetの一括delete()メソッドを使用するのではなく。

https://docs.djangoproject.com/en/1.11/topics/db/queries/#deleting-objects

一括更新(QuerySetオブジェクトの.update()メソッド):

最後に、update()はSQLレベルで更新を行うため、モデルでsave()メソッドを呼び出したり、pre_saveまたはpost_saveシグナルを発行したりしないことを理解してください(Model.save(を呼び出した結果) ))。カスタムのsave()メソッドを持つモデルの一連のレコードを更新する場合は、それらをループしてsave()を呼び出します。

https://docs.djangoproject.com/en/2.1/ref/models/querysets/#update

1
valex