Djangoシグナルとsaveメソッドのオーバーライド
-
05-07-2019 - |
質問
これで頭を包み込むことができません。現在、次のようなモデルがいくつかあります。
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平均を再計算する必要があります。現在、オーバーライドされたsaveメソッドを使用しています。 Djangoのシグナルディスパッチャを使用することに何か利点はありますか?
解決
保存/削除信号は、問題のモデルに完全に固有ではない変更を行う必要がある場合、または共通の何かを持つモデルに適用できる場合、またはモデル全体で使用するように構成できる場合に一般的に有利です。
オーバーライドされた save
メソッドの一般的なタスクの1つは、モデルのテキストフィールドからスラッグを自動生成することです。これは、いくつかのモデルに実装する必要がある場合に、 pre_save
シグナルを使用することでメリットが得られるものの例です。シグナルハンドラーは、slugフィールドの名前とスラッグを生成するフィールド。そのようなものを配置すると、配置した拡張機能はすべてのモデルに適用されます。一意性を確保するために、問題のモデルのタイプに追加しようとしているスラッグを検索します。
再利用可能なアプリケーションは、多くの場合、信号の使用から恩恵を受けます-提供する機能を任意のモデルに適用できる場合、一般的に(やむを得ない場合を除き)、ユーザーがその恩恵を受けるためにモデルを直接変更する必要はありません。
django-mptt では、たとえば pre_saveを使用しました
シグナルは、作成または更新されるモデルのツリー構造を記述するフィールドのセットを管理し、 pre_delete
シグナルは、削除されるオブジェクトとそのオブジェクトのツリー構造の詳細を削除しますその前にオブジェクトのサブツリー全体が削除されます。シグナルを使用しているため、ユーザーはモデルで save
または delete
メソッドを追加または変更する必要はありません。 django-mpttは、管理するモデルを知っています。
他のヒント
尋ねた:
Djangoのシグナルディスパッチャを使用する利点はありますか?
django docsでこれを見つけました:
オーバーライドされたモデルメソッドは、一括操作では呼び出されません
オブジェクトのdelete()メソッドは必ずしも呼び出されないことに注意してください QuerySetを使用して、または カスケード削除。カスタマイズされた削除ロジックが確実に実行されるようにするには、 pre_deleteおよび/またはpost_deleteシグナルを使用できます。
残念ながら、作成または更新するときの回避策はありません save()、pre_save、post_saveのいずれもが 呼ばれます。
From:定義済みモデルメソッドのオーバーライド
信号を使用する場合、関連するスコアモデルが保存されるたびにレビュースコアを更新できます。しかし、そのような機能が必要ない場合、これをシグナルにする理由はわかりません。それはかなりモデルに関連するものです。
これは一種の非正規化です。このきれいなソリューションをご覧ください。インプレース構成フィールドの定義。
一括削除に関するDjangoドキュメントの小さな追加( QuerySet
オブジェクトの .delete()
メソッド):
これは、可能な限り、純粋に実行されることに注意してください SQLなど、個々のオブジェクトインスタンスのdelete()メソッドは プロセス中に必ずしも呼び出されるとは限りません。あなたが提供した場合 モデルクラスのカスタムdelete()メソッドであり、それが 呼び出されると、“手動で”そのモデルのインスタンスを削除する (たとえば、QuerySetを反復処理し、それぞれに対してdelete()を呼び出すことにより オブジェクトを個別に)ではなく、の一括delete()メソッドを使用 QuerySet。
https://docs.djangoproject.com/ ja / 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
長期プロセスを実行する必要があり、保存が完了するのを待っているユーザーをブロックしたくない場合、信号は便利です。