(1) 添加到購物車
前端:
html
<a @click="add_carts" class="add_cart" id="add_cart">加入購物車</a>
js
// 加入購物車
add_carts(){
let url = '/carts/';
axios.post(url, {
sku_id: parseInt(this.sku_id),
count: this.sku_count
}, {
headers: {
'X-CSRFToken':getCookie('csrftoken')
},
responseType: 'json',
withCredentials: true
})
.then(response => {
if (response.data.code == '0') {
alert('添加購物車成功');
this.cart_total_count += this.sku_count;
} else { // 參數錯誤
alert(response.data.errmsg);
}
})
.catch(error => {
console.log(error.response);
})
},
後端
views.py
class CartsView(View):
"""購物車管理"""
def post(self, request):
"""保存購物車"""
# 接收參數
json_dict = json.loads(request.body.decode())
sku_id = json_dict.get('sku_id')
count = json_dict.get('count')
selected = json_dict.get('selected', True) # 可選
# 校驗參數
# 判斷參數是否齊全
if not all([sku_id, count]):
return http.HttpResponseForbidden('缺少必傳參數')
# 校驗sku_id是否合法
try:
SKU.objects.get(id=sku_id)
except SKU.DoesNotExist:
return http.HttpResponseForbidden('參數sku_id錯誤')
# 校驗count是否是數字
try:
count = int(count)
except Exception as e:
return http.HttpResponseForbidden('參數count錯誤')
# 校驗勾選是否是bool
if selected:
if not isinstance(selected, bool):
return http.HttpResponseForbidden('參數selected錯誤')
# 判斷用戶是否登錄
user = request.user
if user.is_authenticated:
# 如果已登錄,操作Redis購物車
redis_conn = get_redis_connection('carts')
pl = redis_conn.pipeline()
# 需要以增量計算的形式保存商品數據
# hincrby方法能實現:如果sku_id在redis中存在,累加該sku_id的count的值;如果sku_id在redis中不存在,新建記錄
pl.hincrby('carts_%s' % user.id, sku_id, count)
# 保存商品勾選狀態
if selected:
pl.sadd('selected_%s' % user.id, sku_id)
# 執行
pl.execute()
# 響應結果
return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})
else:
# 如果用戶未登錄,操作cookie購物車
# 獲取cookie中的購物車數據,並且判斷是否有購物車數據
cart_str = request.COOKIES.get('carts')
if cart_str:
# 將cart_str轉成bytes類型的字符串
cart_str_bytes = cart_str.encode()
# 將cart_str_bytes專程bytes類型的字典
cart_dict_bytes = base64.b64decode(cart_str_bytes)
# 將cart_dict_bytes轉成真正的字典
cart_dict = pickle.loads(cart_dict_bytes)
else:
cart_dict = {}
"""
{
"sku_id1":{
"count":"1",
"selected":"True"
},
}
"""
# 判斷當前要添加的商品在cart_dict中是否存在
if sku_id in cart_dict:
# 購物車已存在,增量計算
origin_count = cart_dict[sku_id]['count']
count += origin_count
cart_dict[sku_id] = {
'count': count,
'selected': selected
}
# 將cart_dict轉成bytes類型的字典
cart_dict_bytes = pickle.dumps(cart_dict)
# 將cart_dict_bytes轉成bytes類型的字符串
cart_str_bytes = base64.b64encode(cart_dict_bytes)
# 將cart_str_bytes轉成字符串
cookie_cart_str = cart_str_bytes.decode()
# 將新的購物車數據寫入到cookie
response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})
response.set_cookie('carts', cookie_cart_str)
# 響應結果
return response
後端邏輯是:
判斷用戶是否登錄------若登錄:使用redis存儲;
redis的hincrby方法:
# 需要以增量計算的形式保存商品數據
# hincrby方法能實現:如果sku_id在redis中存在,累加該sku_id的count的值;如果sku_id在redis中不存在,新建記錄
pl.hincrby('carts_%s' % user.id, sku_id, count)
若未登錄:使用前端cookie存儲
首先了解python的兩個模塊:base64, pickle
序列化(字典--->字符串)
In [1]: import pickle
In [2]: dict = {'1':{'count': 10, 'selected': True}, '2': {'count': 20, 'selected': False}}
In [3]: ret = pickle.dumps(dict)
In [4]: ret
Out[4]: b'\x80\x03}q\x00(X\x01\x00\x00\x001q\x01}q\x02(X\x05\x00\x00\x00countq\x03K\nX\x08\x00\x00\x00selectedq\x04\x88uX\x01\x00\x00\x002q\x05}q\x06(h\x03K\x14h\x04\x89uu.'
In [5]: import base64
In [6]: base64.b64encode(ret)
Out[6]: b'gAN9cQAoWAEAAAAxcQF9cQIoWAUAAABjb3VudHEDSwpYCAAAAHNlbGVjdGVkcQSIdVgBAAAAMnEFfXEGKGgDSxRoBIl1dS4='
In [7]: b = base64.b64encode(ret)
In [8]: cookie_cart_str = b.decode()
In [9]: cookie_cart_str
Out[9]: 'gAN9cQAoWAEAAAAxcQF9cQIoWAUAAABjb3VudHEDSwpYCAAAAHNlbGVjdGVkcQSIdVgBAAAAMnEFfXEGKGgDSxRoBIl1dS4='
dict--->ret=pickle.dumps(dict) --->b=base64.b64encode(ret) --->cookie_cart_str = b.decode() -->cookie_cart_str
反序列化(序列---->字典)
In [10]: b = cookie_cart_str.encode()
In [11]: b
Out[11]: b'gAN9cQAoWAEAAAAxcQF9cQIoWAUAAABjb3VudHEDSwpYCAAAAHNlbGVjdGVkcQSIdVgBAAAAMnEFfXEGKGgDSxRoBIl1dS4='
In [12]: ret = base64.b64decode(b)
In [13]: ret
Out[13]: b'\x80\x03}q\x00(X\x01\x00\x00\x001q\x01}q\x02(X\x05\x00\x00\x00countq\x03K\nX\x08\x00\x00\x00selectedq\x04\x88uX\x01\x00\x00\x002q\x05}q\x06(h\x03K\x14h\x04\x89uu.'
In [14]: dict = pickle.loads(ret)
In [15]: dict
Out[15]: {'1': {'count': 10, 'selected': True}, '2': {'count': 20, 'selected': False}}
b = cookie_cart_str.encode()---->ret = base64.b64decode(b) --->dict = pickle.loads(ret)
這樣做的目的是不以明文的形式將購物車信息放入前端cookie中
後端代碼對於沒有登錄的用戶邏輯是:判斷購物車是否有數據--若有,先反序列化,重新計算後再序列化;若沒有直接新建字典,再序列化。
response.set_cookie('carts', cookie_cart_str)
然後將序列化後的數據放入前端cookie中。
流程分析
點擊“加入購物車”按鈕,觸發Ajax請求:
後端將序列化好的數據發給前端。
可發現前端cookie中存入了序列化的數據。