Django v1.0 documentation

シグナル

revision-up-to:8961 (1.0)

Django には「シグナルディスパッチャ (signal dispatcher)」が組み込まれていま す。シグナルディスパッチャにより、アプリケーションをフレームワークから脱カッ プリングしつつ、フレームワークのどこかで起きたアクションに応じた通知を受け られます。簡単にいえば、シグナルによって、ある「 送信側(sender) 」から 複数の「 受信側(receiver) 」に向けて、何らかのアクションが起きたことを通 知できるのです。シグナルは、たくさんのコードが同じイベントを待ち受けるよう な状況で特に便利です。

Django は、自分自身の特定のアクションを通知するための 組み込みシグナ ル を提供しています。。組み込みシグナルの中には、以下のような 便利なものがあります:

組み込みシグナルの全容と各々の解説は、 組み込みシグナルのドキュメント で解説しています。

シグナルは 自分て定義したり送信したり できます。詳しくは以下を参照し てください。

シグナルを待ち受ける

シグナルを受信するには、シグナルが送信されたときに呼び出される レシーバ(receiver) 関数を登録する必要があります。 HTTP リクエストの処理が 終ったときに呼び出されるシグナルのレシーバを登録して、この仕組みを見てみま しょう。この例では、 request_finished シグナル をレシーバに結びつけます。

レシーバ関数

まず、レシーバ関数を定義します。レシーバは通常の Python の関数やメソッドと して定義します:

def my_callback(sender, **kwargs):
    print "Request finished!"

この関数は固定引数の sender と、ワイルドカードで表現された任意のキーワー ド引数 (**kwargs) をとります。シグナルハンドラは、全てこの形式の引数を とらねばなりません。

sender については 後で 説明するとして、今はまず **kwargs に注目しましょう。シグナルはすべてキーワード引数を伴い、キーワー ド引数の内容はいつでも変更される可能性があります。 request_finished の場合、ドキュメントにキーワー ド引数をもたないと明記されているので、シグナルハンドラを my_callback(sender) と書いていいと思いがちです。

しかしこれは誤っています。実際、 my_callback(sender) のように定義すると Django はエラーを送出します。というのも、将来シグナルに引数が追加されるかも しれず、そのときにもレシーバは新たに追加された引数を扱えねばならないからで す。

レシーバ関数を結びつける

次に、レシーバをシグナルに結びつけます:

from django.core.signals import request_finished

request_finished.connect(my_callback)

これで、 my_callback 関数は、リクエストの処理が終了するたびに呼び出され ます。

シグナル処理のコードはどこにおけばよいのですか?

シグナルの処理や登録のためのコードは、どこでも好きな場所に置けます。 とはいえ、自分の登録したいシグナルが送信されるよりも前に、コードの入っ ているモジュールを早々に import しておきたいいでしょう。そのため、シグ ナルハンドラの登録は models.py に置くのがよいでしょう。

特定のセンダから送信されたシグナルだけを結びつける

シグナルには何度も送信されるものがありますが、その中でも特定のサブセットだ けを受け取りたい場合もあるでしょう。例えば、モデルインスタンスが保存される ときに送信される django.db.models.signals.pre_save を考えましょう。 大抵は、シグナルを受信したいのは すべての モデルの保存時ではなく、 特定の モデルの保存時のはずです。

こうしたケースのために、特定のセンダから送られるシグナルに対してレシーバを 登録できます。 django.db.models.signals.pre_save の場合、センダは インスタンスを保存しようとするモデルなので、以下のようにして、特定のモデル に対してのみシグナルを受信させられます:

from django.db.models.signals import pre_save
from myapp.models import MyModel

def my_handler(sender, **kwargs):
    ...

pre_save.connect(my_handler, sender=MyModel)
これで、保存されるインスタンスが MyModel のインスタンスであるときだけ、
my_handler 関数が呼び出されます。

センダに入るオブジェクトは、シグナルによって異なります。個々のシグナルにつ いての情報は 組み込みシグナルのドキュメント を参照して ください。

シグナルの定義と送信

自分のアプリケーション内でも、シグナルのインフラストラクチャを使ったり、独 自のシグナルを提供したりできます。

シグナルを定義する

class Signal([providing_args=list])

シグナルは全て django.dispatch.Signal のインスタンスです。 providing_args は、シグナルがリスナに対して提供する引数の名前が入ったリ ストです。

例えば:

import django.dispatch

pizza_done = django.dispatch.Signal(providing_args=["toppings", "size"])

上のコードは pizza_done シグナルを作成し、このシグナルが toppingsize という引数をもたらすことを宣言しています。

このリストはいつでも変更できるので、最初の時点で正確に API を定義しておく必 要はありません。

シグナルを送信する

Signal.send(sender, **kwargs)

シグナルを送信するには Signal.send() を呼び出します。 sender を必 ず指定し、必要に応じて追加の引数を指定します。

例えば、 pizza_done シグナルを送信するには、以下のように書きます:

class PizzaStore(object):
    ...

    def send_pizza(self, toppings, size):
        pizza_done.send(sender=self, toppings=toppings, size=size)
        ...