Django e-commerce part15 Post Save Signals for Variations
Variationsの、Post Save Signal
http://127.0.0.1:8000/products/2/ については、まだvariationが登録されていないため、選択肢が空欄になっていると思います。
Signalの公式ドキュメント:
Signals | Django documentation | Django
- その中でも、post_save メソッドを使う post_save = save()メソッドの処理の最後に呼び出される。 pre_save= save()メソッドの処理の最初に呼び出される。 signalは、例えば、saveを処理が行われるときに、そのsignalを受け取って処理する関数のこと。
Signals | Django documentation | Django
- products/models.py post_saveメソッドをimportする。
from django.db.models.signals import post_save
- products/models.py
def product_post_saved_receiver(sender, instance, created, *args, **kwargs): print sender print instance print created # post_save.connect(product_post_saved_receiver, sender=Product) # signal.connect()で、シグナルが送信されたときに呼び出される関数(レシーバー関数)を設定する。
- ちょっとここはよく分からない。
post_saveを使うには、
- コールバック関数(レシーバ関数)を設定する
- レシーバ関数は、以下の形式になる。
def my_callback(sender, **kwargs): print "Request finished!"
この関数は固定引数の sender と、ワイルドカードで表現された任意のキーワー ド引数 (kwargs) をとります。シグナルハンドラは、全てこの形式の引数を とらねばなりません。 どうも、kwargsは、追加の引数に対応するために、必須ぽいです。 senderは、signalを送信してくるclass?ぽいな。 sender – シグナルを受け取るための特定のセンダを指定します。詳細は 特定のセンダから送信されたシグナルだけを結びつける を参照してください。 3. レシーバ関数をsignalと結びつける。
from django.core.signals import request_finished request_finished.connect(my_callback)
デコレーターもつかるが、ちょっとよく分からないので、スキップ
* まとめると、post_saveは、saveのsignalが来たときに、receiver関数が呼び出される! とシンプルに考えればよし!?
詳細は以下に説明があるが、自分のような若輩者には難しい。。。 シグナル — Django 1.4 documentation
- それを踏まえて再度以下の関数を検証する。
def product_post_saved_receiver(sender, instance, created, *args, **kwargs): print sender print instance print created post_save.connect(product_post_saved_receiver, sender=Product)
saveのsignalがProduct(sender)から来たときに、 product_post_saved_receiver が呼び出される。
- 実際にProductを保存してみると以下のようにprintされる
このようにみると、sender, instance, created(新規で作られたかどうか?)は、デフォルトのkeyぽい。 テストはとりあえず無事終了!
product_post_save_receiverを編集してみる。
products/models.py
def product_post_saved_receiver(sender, instance, created, *args, **kwargs): product = instance # productに、instanceを代入 variations = product.variation_set.all() # variationsに、instanceが、foreignkey担っているvariationを全て取得する。 if variations.count()==0: # もし、variationsが0ならば、 new_var = Variation() # new_varに、Variationのinstanceを代入する new_var.product = product # Variationのinstance には、productのinstance(__str__のところ)を代入 new_var.title = "Default" # title は、"Default" new_var.price = product.price # price は、price new_var.save() #上記の内容で、new_var(instance)を保存する。Variation().save()という意味? # variations = Variation.objects.filter(product=product) #ちなみに、上記は、 variations = product.variation_set.all()と同じ意味のコード # 多分、variation_set が便利(foreignkeyとして関連づけられているclass_set で、そのclassのinstanceをゲットできる。 post_save.connect(product_post_saved_receiver, sender=Product) # Productから、save signalが送られてきたら、product_post_saved_receiverを呼び出す。
- product_detail.html の方も修正しておく templates/product_detail.html
{% if object.variation_set.count > 1 %} <select class='form-control'> {% for vari_obj in object.variation_set.all %} <option value="{{ vari_obj.id }}">{{ vari_obj }}</option> {% endfor %} </select> {% endif %} <br/> <a href="#">Add to Cart</a>
という感じで、1より小さい場合にオプションボックスを表示させないようにする。
また、最後に、Add to Cart のリンクを作成しておく。