最近在用django restframe框架做一个商城项目,有一个关于购物车的业务逻辑,是用cookie和redis存储的购物车信息,在这里记录一下。
完成一个商城项目,如果不做一个购物车,就是十分可惜的。我们先来分析一下业务逻辑,参照,京东、淘宝等大型电商网站,可以发现,对于登录用户以及未登录用户,都是可以使用购物车功能。所以首先我们将这两种情况区分开来,采用不同的存储方式。先来看一下已登录用户,购物车其实类似我们在游览网页时的收藏功能,用于收藏用户喜欢的一些商品,用户使用频率较高,所以我们应该优先使用内存型的数据库redis进行存储,这样查询起来会更快。确定了使用什么数据库,我们还要在思考一下用什么形式存储数据。我使用的是2.x版本的redis,共有string,hash,set,zset,list等几种存储格式。hash类似python中的字典,其他几种格式也和python中对应的list,set,string类似。需要额外注意的是,redis中所有数据都是以bytes方式存储。再来看一下我们的需求,对于一个购物车,我们可以看到商品以及商品数量,以及是否勾选商品。对于商品,我们可以只存储其商品id,需要用到商品信息时在进行查询,而对于勾选状态,我们则需要用一个额外的字段存储,由于每个人的购物车都应该是独立的个体,所有我们可以用用户的id进行存储,我们会发现要存储上述信息,我们只使用一种存储格式是很难完成的,所以我们可以考虑用两个分别存储。商品及数量我们可以考虑使用hash格式进行存储,用key存储商品id,value存储商品数量,用户id进行区分不同的购物车,而对于勾选状态,我们可以用set进行存储,对于不同的商品只有勾选和未勾选状态,我们可以考虑将已经勾选的商品的id进行存储,在set内的商品即为勾选,不在的即为未勾选。登录用户搞定了我们再来看看未登录用户,未登录用户的话,应该只在本机使用,而在登录时进行合并处理,所以我们没有必要存储到数据库中,同时,在登录时要进行合并操作,我们可以想到cookie,在登录请求时,游览器会自己带上cookie,所以我们可以考虑用cookie存储,存储格式可以用一个嵌套的大字典。分析完毕,就开始进行真正的操作把。
增删改查四个逻辑,首先来看看新增把。对于新增购物车,我们需要接受的参数为商品id和数量,而勾选状态可以默认为勾选,添加购物车后可以在进行修改,这里的商品我们采用sku的形式进行存储。新增操作的话是post请求,我们可以在视图类中定义一个post方法来接受新增请求,这里的视图类我们继承的是APIView。这里我只写视图方法,对于序列化器就不做描写。首先我们应该接受前端传过来的参数,并进行校验,校验完成后,对用户登录状态进行判断(我是采用JWT来进行用户登录状态存储),对于不同用户,采用不同方式存储购物车信息。
def post(self, request): # 接受参数并传入序列化器进行校验 serializer = CartSerializer(request.data) # 判断是否验证通过,若未通过未抛出验证错误,DRF会自己处理验证错误 serializer.is_valid(raise_exception=True) # 取出校验后的数据 sku_id = serializer.validated_data['sku_id'] count = serializer.validated_data['count'] selected = serializer.validated_data['selected'] # 判断用户登录状态,这里可以参照我之前写的django中的user验证 try: user = request.user except Exception: user = None if user and user.is_authenticated: # 创建redis链接,这里用到了django_redis扩展 redis_conn = get_redis_connection('cart') pl = redis_conn.pipeline() # 建立管道,一次提交命令,不用多次链接redis pl.hincrby("cart_%s"%user.id, sku_id, count) # 向字段名为"cart_%s"%user.id的哈希中插入key为sku_id,value为count的数据, count可以为负数,负数则为减 if selected: pl.sadd("cart_selected_%s"%user.id, sku_id) # 若勾选,则把商品的id存入