カートを実装してたらはまった

今まであまりセッションを意識せずに開発してたせいか、つまらないことですごくはまったのでメモしておく。

django のセッションはシンプルで、 request.session を辞書ライクに使えばいい。
なので今回は、商品名の配列とか合計金額を格納してカートを実装することにした。

def cart_add(request):
    ''' カートに商品を追加する。
    '''
    cart = request.session.get('cart', { 'total' : 0, 'items':[] })
    cart['total'] += int(request.POST.get('price', 0))
    cart['items'].append(request.POST.get('itemname', '')
    request.session['cart'] = cart
    #略

def cart_list(request):
    ''' カートの中身を表示する。
    '''
    return render_to_response('cart_list.html', {
        'cart' : request.session.get('cart', { 'total' : 0, 'items':[] }),
    }, RequestContext(request))

def cart_clear(request):
    ''' カートの中身を消去する。
    '''
    if 'cart' in request.session:
        request.session['cart'] = { 'total' : 0, 'items':[] }

で、カートの初期値が何回も登場するので、一個所にまとめることにした。

CART_EMPTY = {
    'total_price' : 0,
    'items' : [],
}

そうすると、cart_clearを実行してもなぜかカートの中身がクリアされなかったり、IEとFirefoxでカートの中身が共有されたりと、かなりヤバい現象が発生した。
前者については、セッションですらキャッシュが効くのか、とあまり深く考えていなかった。だが後者はいくらなんでもおかしすぎる。djangoがそんな仕様のわけがない。

原因としては呆れるほど単純だった。上記の書き方だと、CART_EMPTYという名前のオブジェクトをあちこちで共有してるにすぎない。だからカートの中身も共有されてしまってたんですな。変数名が大文字だからと言って、特別なわけじゃないんだよな・・・

で、とりあえずlambdaを使って毎回オブジェクトを生成するようにしたら、あっさり解決しました。我ながら情けない・・・

CART_EMPTY = (lambda:{
    'total_price' : 0,
    'items' : [],
})()