购物车模块实现
-
添加到购物车: 对前端发送的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