Djangoroidの奮闘記

python,django,angularJS1~三十路過ぎたプログラマーの奮闘記

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を使うには、

  1. コールバック関数(レシーバ関数)を設定する
  2. レシーバ関数は、以下の形式になる。
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 iphone →instance False →created

  • このようにみると、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 のリンクを作成しておく。