購物車模塊實現
-
添加到購物車: 對前端發送的sku_id, count, selected進行相應的存儲
# 先定義序列化器, 用途是對sku_id,count進行驗證 class CartSerializer(serializers.Serializer): sku_id = serializers.IntegerField(min_value=1) count = serializers.IntegerField(min_value=1) selected = serializers.BooleanField(default=True) def validate(self,attrs): try: sku = SKU.objects.get(id=atttrs['sku_id']) except: raise serializers.ValidationError('商品不存在') if count > sku.stock: raise serializers.ValidationError('庫存不足') return attrs # 定義視圖, 實現業務邏輯 class CartView(APIView): # 重寫驗證方法, 不在進入視圖前就檢查JWT def perform_authentication(self, request): pass # 在商品詳情頁添加購物車 def post(self,request): serializer=CartSerializer(data=request.data) serializer.is_valid(raise_exception=True) # 獲取數據 sku_id=request.data.get('sku_id') count=request.data.get('count') selected=request.data.get('selected') # 判斷用戶登錄 try: user=request.user except: user=None if user: # 在redis中存儲,redis存儲的數據不需要加密 conn = get_redis_connection('cart') conn.hincrby('cart_%s'%user.id,sku_id,count) if selected: conn.sadd('cart_selected_%s'%user.id,sku_id) return Response(serializer.data) else: cart=request.COOKIES.get('cart') if cart: cart=pickle.loads(base64.b64decode(cart)) else: cart={} sku = cart.get(sku_id) if sku: count+=int(sku.get('count')) cart[sku_id]={ 'count':count, 'selected':selected } cart_cookie=base64.b64encode(pickle.dumps(cart)) response=Response(serializer.data) response.set_cookie('cart',cart_cookie,60*60*24) return response
-
查詢購物車數據, 對redis或者cookie中存儲的數據進行讀取和展示
# 序列化器用作返回需要的sku對象字段 class CartSKUSerializer(serializers.ModelSerializer): count = serializers.IntegerField() selected = serializers.BooleanField() class Meta: model = SKU fields = ('id', 'count', 'name', 'default_image_url', 'price', 'selected') # 在上個視圖中寫get方法 class CartView(APIView): ... def get(self,request): # 判斷用戶是否登錄 try: user = request.user except Exception: user = None if user: conn = get_redis_connection('cart') redis_skus = conn.hgetall('cart_%s'%user.id) redis_selecteds=conn.smembers('cart_selected_%s'%user.id) cart={} for sku_id,count in redis_skus.items(): cart[sku_id]={ 'count':count, 'selected':sku_id in redis_selecteds } else: cart = request.COOKIES.get('cart') if cart: cart=pickle.loads(base64.b64.decode(cart)) else: cart={} skus = SKU.objects.filter(id__in=cart.keys()) for sku in skus: sku.count=cart[sku.id]['count'] sku.selected=cart[sku.id]['selected'] serializer=CartSKUSerializer(skus,many=True) return Response(serializer.data)
-
修改是對redis和cookie中存儲數據的修改
class CartView(APIView): ... # 接受數據, 驗證數據 def put(self, request): serializer = CartSerializer(data=request.data) serializer.is_valid(raise_exception=True) sku_id = serilaizer.validated_data.get('sku_id') count = serilaizer.validated_data.get('count') selected = serilaizer.validated_data.get('selected') try: user = request.user except: user = None if user: conn = get_redis_connection('cart') conn.hset('cart_%s'%user.id, sku_id, count) if selected: conn.sadd('cart_selected_%s'%user.id, sku_id) else: conn.srem('cart_selected_%s'%user.id, sku_id) return Response(serializer.data) else: cart = request.COOKIES.get('cart') if cart: cart=pickle.loads(base64.b64decode(cart)) else: cart={} cart[sku_id]={ 'count':count, 'selected':selected } cookie_cart=pickle.dumps(base64.b64encode(cart)) response=Response(serializer.data) response.set_cookie('cart',cookie_cart,60*60*24) return response
-
刪除購物車數據, 根據sku_id刪除redis和cookie中的數據
class CartView(APIView): ... def delete(self, request): # 這裏手動進行數據認證 sku_id = request.data.get('sku_id') try: sku = SKU.objects.get(id=sku_id) except: return Response('商品id不存在') # 進行用戶驗證 try: user=request.user except: user=None if user: conn=get_redis_connection('cart') conn.hdel('cart_%s'%user.id, sku_id) conn.srem('cart_selected_%s'%user.id, sku_id) return Response('OK') else: cart=request.COOKIES.get('cart') if cart: cart=pickle.loads(base64.b64decode(cart)) if sku_id in cart: del cart[sku_id] cart=base64.b64encode(pickle.dumps(cart)) response=.set_cookie('cart',cart,60*60*24) return Response('OK')
-
購物車全選, 是前端發送selected請求, 後端統一修改存儲的sku_id的狀態
# 首先是序列化器的驗證, 驗證前端發送的selected數據是否正確 class CartSelectAllSerializer(serializers.Serializer): selected=serializers.BooleanField() # 視圖的作用是業務邏輯的處理了 class CartSelectAllView(APIView): # 重寫父類的用戶驗證方法,不在進入視圖前就檢查JWT def peiform_authentication(self, request): pass def put(self, request): # 驗證數據 serializer = CartSelectAllSerializer(data=request.data) serializer.is_valid(raise_exception=True) selected = serializer.validated_data['selected'] # 驗證用戶是否登錄 try: user = request.user except: user=None # 如果用戶登錄了 if user is not None and user.is_authenticated: conn=get_redis_connection('cart') # 這是取出一個sku_id和count組成的字典 cart_dict = conn.hgetall('cart_%s'%user.id) # 取出所有sku_id sku_ids = cart_dict.keys() # 如果是全選的話 if selected: conn.sadd('cart_selected_%s'%user.id, *sku_ids) # 如果是全不選的話 else: conn.srem('cart_selected_%s'%user.id, *sku_ids) return Response('OK') else: # 修改cookie cart=request.COOKIES.get('cart') cart=pickle.loads(base64.b64decode(cart)) response=Response('OK') if cart: cart_new={} for sku_id, data in cart.item(): cart_new[sku_id]={ 'count':data['count'], 'selected':selected } cart=base64.b64encode(pickle.dumps(cart_new)) response.set_cookie('cart',cart,60*60*24) return response
-
合併登錄購物車, 合併普通登錄和QQ登錄, 所以封裝函數實現
# 函數需要參數request,user,response # request獲取cookie,user是user.id,response是響應對象 def merge_cart_cookie_to_rdeis(request,user,response): # 取出cart數據 cart=request.COOKIES.get('cart') cart=pickle.loads(base64.b64decode(cart)) # 把數據分開存儲在redis中 if cart: cart_dict={} sku_list=[] sku_remove=[] for sku_id,data in cart.items(): cart_dict[sku_id]=data['count'] if data['selected']: sku_list.append(sku_id) else: sku_remove.append(sku_id) if cart_dict: conn=get_redis_connection('cart') conn.hset('cart_%s'%user.id, cart_dict) if sku_list: conn.sadd('cart_selected_%s'%user.id, *sku_list) if sku_remove: conn.srem('cart_selected_%s'%user.id, *sku_remove) response.delete_cookie('cart') return response
-
爲了在登錄中獲取user對象, 要修改登錄視圖的功能
class UserAuthorizeView(ObtainJSONWebToken): def post(self,request,*args,**kwargs): response=super().post(request,*args,**kwargs) serializer=self.get_serializer(data_request.data) if serializer.is_valid(): user=serializer.validated_data.get('user') # 對response進行了修改 response=merge_cart_cookie_to_redis(request, user, response) return response
-
在創建QQ用戶時, 改寫序列化器, 在視圖對象中補充user對象屬性, 以便在視圖中使用
def create(self,validated_data): ... self.context['view'].user=user return user # 修改views視圖, 尤其是post方法 def post(self, request, *args, **kwargs): response=merge_cart_cookie_to_redis(request, self.user, response) return response