Djangoシグナルとsaveメソッドのオーバーライド


89

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

 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のシグナルディスパッチャーを使用することに何かメリットはありますか?

回答:


84

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

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

再利用可能なアプリケーションは、多くの場合、シグナルを使用することで恩恵を受けます。それらが提供する機能を任意のモデルに適用できる場合、一般に(避けられない場合を除いて)ユーザーがその恩恵を受けるためにモデルを直接変更する必要はありません。

ジャンゴ-MPTT、例えば、私が使用pre_save作成または更新されようとしているモデルのツリー構造を記述するフィールドのセットを管理するための信号をpre_deleteオブジェクトのツリー構造の詳細を除去するための信号が削除され、その全体をその前のオブジェクトのサブツリーとそれらは削除されます。信号を使用しているため、ユーザーが追加または変更する必要はありませんsaveか、delete彼らはちょうど彼らがそれを管理したいモデルジャンゴ-MPTTが知っているように持って、彼らのモデルのメソッドは、この経営者は彼らのために行われています。


シグナルハンドラが例外をトリガーした場合はどうなりますか?例外をトリガーするべきではないと思います。そうしないと、適切ではありません。私が間違っている?
X-ゆり

20

あなたは尋ねました:

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

私はこれをdjangoのドキュメントで見つけました:

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

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

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

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


3
Django管理リストビューは一括削除を使用しています...この一口に出くわすまで混乱していました。
N.Balauro 2017

7
また、「残念ながら、save()、pre_save、post_saveは呼び出されないため、オブジェクトを一括で作成または更新する場合の回避策はありません。」-ですから、これはこれらの方法の間のトレードオフではないと思います。
Cory

これは両方のメソッドに当てはまるので、答えは次のとおりです。「いいえ、saveメソッドをオーバーライドするのではなく、シグナルを使用するメリットはありません」?
Flimm

3

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



1

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

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

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

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

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

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


これは両方に当てはまりませんか?
Flimm
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.