添加到購物車
阿新 • • 發佈:2018-07-31
serialize rfi fault 序列化 framework param 重寫 cors default
1. 後端接口設計
請求方式 : POST /cart/
請求參數: JSON 或 表單
參數 | 類型 | 是否必須 | 說明 |
---|---|---|---|
sku_id | int | 是 | 商品sku id |
count | int | 是 | 數量 |
selected | bool | 否 | 是否勾選,默認勾選 |
返回數據: JSON
參數 | 類型 | 是否必須 | 說明 |
---|---|---|---|
sku_id | int | 是 | 商品sku id |
count | int | 是 | 數量 |
selected | bool | 是 | 是否勾選,默認勾選 |
訪問此接口,無論用戶是否登錄,前端請求都需攜帶請求頭Authorization,由後端判斷是否登錄
2. 後端實現
因為前端可能攜帶cookie,為了保證跨域請求中,允許後端使用cookie,確保在配置文件有如下設置
CORS_ALLOW_CREDENTIALS = True
創建應用carts。
在carts/serialziers.py中創建序列化器
class CartSerializer(serializers.Serializer):
"""
購物車數據序列化器
"""
sku_id = serializers.IntegerField(label=‘sku id ‘, min_value=1)
count = serializers.IntegerField(label=‘數量‘, min_value=1)
selected = serializers.BooleanField(label=‘是否勾選‘, default=True)
def validate(self, data):
try:
sku = SKU.objects.get(id=data[‘sku_id‘])
except SKU.DoesNotExist:
raise serializers.ValidationError(‘商品不存在‘)
if data[‘count‘] > sku.stock:
raise serializers.ValidationError(‘商品庫存不足‘)
return data
編寫視圖:
註意:因為前端請求時攜帶了Authorization請求頭(主要是JWT),而如果用戶未登錄,此請求頭的JWT無意義(沒有值),為了防止REST framework框架在驗證此無意義的JWT時拋出401異常,在視圖中需要做兩個處理
- 重寫perform_authentication()方法,此方法是REST framework檢查用戶身份的方法
- 在獲取request.user屬性時捕獲異常,REST framework在返回user時,會檢查Authorization請求頭,無效的Authorization請求頭會導致拋出異常
在carts/views.py中創建視圖
class CartView(APIView):
"""
購物車
"""
def perform_authentication(self, request):
"""
重寫父類的用戶驗證方法,不在進入視圖前就檢查JWT
"""
pass
def post(self, request):
"""
添加購物車
"""
serializer = CartSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
sku_id = serializer.validated_data.get(‘sku_id‘)
count = serializer.validated_data.get(‘count‘)
selected = serializer.validated_data.get(‘selected‘)
# 嘗試對請求的用戶進行驗證
try:
user = request.user
except Exception:
# 驗證失敗,用戶未登錄
user = None
if user is not None and user.is_authenticated:
# 用戶已登錄,在redis中保存
redis_conn = get_redis_connection(‘cart‘)
pl = redis_conn.pipeline()
# 記錄購物車商品數量
pl.hincrby(‘cart_%s‘ % user.id, sku_id, count)
# 記錄購物車的勾選項
# 勾選
if selected:
pl.sadd(‘cart_selected_%s‘ % user.id, sku_id)
pl.execute()
return Response(serializer.data, status=status.HTTP_201_CREATED)
else:
# 用戶未登錄,在cookie中保存
# {
# 1001: { "count": 10, "selected": true},
# ...
# }
# 使用pickle序列化購物車數據,pickle操作的是bytes類型
cart = request.COOKIES.get(‘cart‘)
if cart is not None:
cart = pickle.loads(base64.b64decode(cart.encode()))
else:
cart = {}
sku = cart.get(sku_id)
if sku:
count += int(sku.get(‘count‘))
cart[sku_id] = {
‘count‘: count,
‘selected‘: selected
}
cookie_cart = base64.b64encode(pickle.dumps(cart)).decode()
response = Response(serializer.data, status=status.HTTP_201_CREATED)
# 設置購物車的cookie
# 需要設置有效期,否則是臨時cookie
response.set_cookie(‘cart‘, cookie_cart, max_age=constants.CART_COOKIE_EXPIRES)
return response
在carts中新建constants.py 常量文件
# 購物車cookie的有效期
CART_COOKIE_EXPIRES = 365 * 24 * 60 * 60
添加到購物車