博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Django实战---商城购物车的增删改、显示和合并购物车
阅读量:2094 次
发布时间:2019-04-29

本文共 13732 字,大约阅读时间需要 45 分钟。


购物车数据存储方案

  1. 存储数据说明

    如何描述一条完整的购物车记录? 用户itcast,选择了两个 iPhone8 添加到了购物车中,状态为勾选 一条完整的购物车记录包括:用户、商品、数量、勾选状态。 存储数据: user_id、sku_id、count、selected
  2. 存储位置说明

    购物车数据量小,结构简单,更新频繁,所以我们选择内存型数据库Redis进行存储。 存储位置:Redis数据库

redis数据格式

Hash  字典格式  cart_USER_ID {sku_id:count}   商品id和数量set  集合    selected_USER_ID   [sku_id]   是否被选中

用户未登录可以添加购物车

把数据添加到cookie 登录之后再存入redis

cookie数据格式 json字符串

cart = {	sku_id:{count:数量,selected:布尔值  是否选中},	xxx: {xxx: xxx, xxx:xxx}}

购物车的添加和显示

购物车添加
  • 流程:

    1. 获取参数  商品的id 和 数量  2. 校验参数  3. 判断用户是否登录    	3.1 如果登录  		3.1.1 连接redis  数据存入redis  		  	3.2 没有登录  		3.2.1 取出cookie  		3.2.2 如果有cookie就解码  		3.2.3 没有cookie就创建新的字典来存放数据 方便存入cookie  		3.2.4 如果商品已经存在购物车再添加就 已有数量+=添加数量  		3.2.5 组织数据存入字典  		3.2.6 稍微加密存入cookie

代码

class CartsView(View):    def post(self, request):        """        购物车添加        :param request:        :return:        """        # 1. 获取参数  商品id 和 商品数量        json_data = json.loads(request.body)        sku_id = json_data.get('sku_id')        count = json_data.get('count')        # 校验参数  是否存在该商品        try:            SKU.objects.get(id=sku_id)        except Exception as e:            print(e)            return JsonResponse({
'code': 400, 'errmsg': '商品不存在'}) # 数量是否是数字 try: count = int(count) except Exception as e: print(e) return JsonResponse({
'code': 400, 'errmsg': '参数错误'}) # 判断用户是否登录 user = request.user # 如果登录存入redis if user.is_authenticated: # 连接redis redis_conn = get_redis_connection('carts') # 存入hash 字典 cart_userId {sku_id:count} redis_conn.hset('cart_%s' % user.id, sku_id, count) # 存入set集合 是否选中 selected_userId [sku_id1,sku_id2,sku_id3] redis_conn.sadd("selected_%s" % user.id, sku_id) return JsonResponse({
'code': 0, 'errmsg': 'ok'}) # 没有登录购物车数据存入cookie else: import base64 import pickle # 先获取cookie cart_cookie = request.COOKIES.get('cart') # 如果有cookie就解码 base64解码 pickle二进制数据转换 if cart_cookie: carts = pickle.loads(base64.b64decode(cart_cookie)) # 没有就创建新字典 else: carts = {
} # 如果商品已经存在购物车 就把数量+1 if sku_id in carts: count_ori = carts[sku_id]['count'] count += count_ori # 组织数据存入cookie carts[sku_id] = {
'count': count, 'selected': True } # 稍微加密一下 carts_bytes = pickle.dumps(carts) b64carts = base64.b64encode(carts_bytes) # 存入cookie response = JsonResponse({
'code': 0, 'errmsg': 'ok'}) response.set_cookie('cart', b64carts.decode(), max_age=3600 * 24 * 10) return response
购物车显示
  • 流程

    1. get请求查看购物车  判断用户是否登录  	如果登录:  		1.1 连接redis  取出购物车和是否被选中的数据  		1.2 组织成字典数据  carts = {数据}  	没有登录:  		1.1取出cookie  		1.2 如果有cookie就解码 没有cookie就创建一个空字典数据 carts={数据}  2. 取出购物车数据内所有的key  为sku_id的列表  3. 查询数据库内所有商品    根据id查询出在购物车列表内的数据  4. 组织数据返回给前端

代码

class CartsView(View):    def get(self, request):        # 判断用户是否登录        user = request.user        if user.is_authenticated:            # 如果登录连接redis            redis_conn = get_redis_connection('carts')            # 取出redis内的所有购物车数据            sku_id_count = redis_conn.hgetall('cart_%s' % user.id)            # 取出所有选中的列表            selected_sku_ids = redis_conn.smembers('selected_%s' % user.id)            # 组织数据            carts = {
} # redis取出是二进制数据 要强转一下 for sku_id, count in sku_id_count.items(): carts[int(sku_id)] = {
'count': int(count), 'selected': sku_id in selected_sku_ids } else: # 没有登录取出cookie cart_cookie = request.COOKIES.get('cart') # 有cookie 就解码 没有cookie就创建一个空字典 if cart_cookie: carts = pickle.loads(base64.b64decode(cart_cookie)) else: carts = {
} # 取出数据中所有的key 为sku_id sku_ids = carts.keys() # 查询所有商品 返回出id在购物车列表内的 skus = SKU.objects.filter(id__in=sku_ids) # 组织数据 id name price 图片 数量 是否被选中 sku_list = [] for sku in skus: sku_list.append({
'id': sku.id, 'name': sku.name, 'price': sku.price, 'default_image_url': sku.default_image.url, 'count': carts[sku.id]['count'], 'selected': carts[sku.id]['selected'], }) # 返回数据 return JsonResponse({
'code': 0, 'errmsg': 'ok', 'cart_skus': sku_list})

修改购物车数据

  • 页面

    在这里插入图片描述

  • 流程

    1. 获取前端参数  商品id  数量 和 是否被选中  2. 校验参数  3. 判断用户是否登录   	登录:  		3.1 连接redis    		3.2 修改数据  		3.3 组织返回前端数据  	没有登录:  		3.1 取出cookie  		3.2 解码  		3.3 修改数据  		3.4 加密  		3.5 组织返回前端的数据  		3.6 返回存入cookie

代码

class CartsView(View):    def put(self, request):        # 获取参数  数量  是否选中 和 商品id        json_data = json.loads(request.body)        count = json_data.get('count')        selected = json_data.get('selected')        sku_id = json_data.get('sku_id')        # 校验参数  商品是否真实存在  数量是否是数字 selected是否是布尔值        try:            SKU.objects.get(id=sku_id)        except Exception as e:            print(e)            return HttpResponseBadRequest('商品不存在')        try:            count = int(count)        except Exception as e:            print(e)            return HttpResponseBadRequest('参数错误')        if not isinstance(selected, bool):            return HttpResponseBadRequest('商品不存在')        # 判断用户是否登录        user = request.user        if user.is_authenticated:            # 登录连接redis            redis_conn = get_redis_connection('carts')            # 修改数据            redis_conn.hset('cart_%s' % user.id, sku_id, count)            # 修改是否被选中            if selected:                redis_conn.sadd('selected_%s' % user.id, sku_id)            else:                redis_conn.srem('selected_%s' % user.id, sku_id)            # 组织返回前端的数据            cart_sku = {
'count': count, 'selected': selected, 'sku_id': sku_id, } return JsonResponse({
'code': 0, 'errmsg': 'ok', 'cart_sku': cart_sku}) else: # 没有登录 取出cookie cart_cookie = request.COOKIES.get('cart') # 解码 carts = pickle.loads(base64.b64decode(cart_cookie)) # 修改数据 carts[sku_id]['count'] = count carts[sku_id]['selected'] = selected # 稍微加密 carts_bytes = pickle.dumps(carts) b64carts = base64.b64encode(carts_bytes) # 组织返回前端的数据 cart_sku = {
'count': count, 'selected': selected, 'sku_id': sku_id, } # 添加到cookie response = JsonResponse({
'code': 0, 'errmsg': 'ok', 'cart_sku': cart_sku}) response.set_cookie('cart', b64carts.decode(), max_age=3600 * 24 * 10) return response

购物车删除

  • 流程:

    1. 获取参数  2. 校验参数  3. 判断用户是否登录  	登录:  		3.1 连接redis  		3.2 删除数据  		3.3 返回响应  	没有登录:  		3.1 获取cookie  		3.2 解码  		3.3 在cookie字典内删除用户要删除的商品id  		3.4 设置cookie  		3.5 返回响应

代码

class CartsView(View):    def delete(self, request):        # 获取参数  要删除购物车内哪一个商品        json_data = json.loads(request.body)        sku_id = json_data.get('sku_id')        #  校验参数        try:            SKU.objects.get(id=sku_id)        except Exception as e:            print(e)            return HttpResponseBadRequest('商品不存在')        # 判断用户是否登录        user = request.user        if user.is_authenticated:            # 如果登录 连接redis            redis_conn = get_redis_connection('carts')            # 删除数据            redis_conn.hdel('cart_%s' % user.id, sku_id)            redis_conn.srem('selected_%s' % user.id, sku_id)            # 返回响应            return JsonResponse({
'code': 0, 'errmsg': 'ok'}) else: # 没有登录 获取cookie cart_cookie = request.COOKIES.get('cart') # 解码 carts = pickle.loads(base64.b64decode(cart_cookie)) # 删除cookie内的该商品 del carts[sku_id] # 加密 carts_bytes = pickle.dumps(carts) base64_carts = base64.b64encode(carts_bytes) # 设置cookie 返回响应 response = JsonResponse({
'code': 0, 'errmsg': 'ok'}) response.set_cookie('cart', base64_carts.decode(), max_age=3600 * 24 * 10) return response

全选按钮的逻辑

  • 页面

    在这里插入图片描述

  • 流程

    1. 获取参数  selected 布尔值 True为勾选   False为不勾选  2. 校验参数  3. 判断用户是否登录  	登录:  		3.1 连接redis  		3.2 取出购物车数据  获取到购物车内所有的商品id  		3.3 把所有的商品id添加到存放是否选中的set集合中(自动去重)  		3.4 返回响应  	没有登录:  		3.1 取出cookie  		3.2 解码  		3.3 如果勾选修改selected都为True  反之则设置为False  		3.4 加密  		3.5 设置cookie  		3.6 返回响应

代码

class CartsSelect(View):    def put(self, request):        # 获取参数  selected全选按钮是否勾选  布尔值        json_data = json.loads(request.body)        selected = json_data.get('selected')        # 校验参数        if not isinstance(selected, bool):            return HttpResponseBadRequest('商品不存在')        # 判断用户是否登录        user = request.user        if user.is_authenticated:            # 如果登录  连接redis            redis_conn = get_redis_connection('carts')            # 获取到所有购物车数据            cart_list = redis_conn.hgetall('cart_%s' % user.id)            # 取出key  key为商品id            cart_key_list = cart_list.keys()            # 遍历商品id            for key in cart_key_list:                # 如果全选选中  就把所有商品id添加到set集合  不用去重 因为set集合自动去重                if selected:                    redis_conn.sadd('selected_%s' % user.id, key)                # 如果没有勾选  就把set集合内所有商品id删除                else:                    redis_conn.srem('selected_%s' % user.id, key)            return JsonResponse({
'code': 0, 'errmsg': 'ok'}) else: # 没有登录就获取cookie cart_cookie = request.COOKIES.get('cart') # 解码 carts = pickle.loads(base64.b64decode(cart_cookie)) # 遍历字典 拆包 k为sku_id v 为 {count:xxx,selected:bool} for k, v in carts.items(): # 如果选中 就把所有的sku_id的selected设置为True if selected: v['selected'] = True # 没有选中则设置为False else: v['selected'] = False # 加密 b64carts = base64.b64encode(pickle.dumps(carts)) # 设置cookie 返回响应 response = JsonResponse({
'code': 0, 'errmsg': 'ok'}) response.set_cookie('cart', b64carts.decode(), max_age=3600 * 24 * 10) return response

主页购物车下拉框显示

页面

鼠标移动到购物车显示数据

在这里插入图片描述

前端需要的数据格式

在这里插入图片描述

请求方式

在这里插入图片描述
流程

1. 获取用户对象判断有没有登录2. 登录了:		查询redis中的购物车数据	没有登录:		查询cookie中的购物车数据3. 取出商品数据添加到列表返回

代码

class CartsSimpleView(View):    def get(self, request):        # 获取用户对象        user = request.user        # 组织数据的列表        cart_skus = []        # 如果用户存在就去连接redis取出购物车数据        if user.is_authenticated:            redis_conn = get_redis_connection('carts')            cart_data = redis_conn.hgetall('cart_%s' % user.id)            sku_id_list = cart_data.keys()                        for sku_id in sku_id_list:                count = int(cart_data.get(sku_id))                sku = SKU.objects.get(id=int(sku_id))                # 组织数据添加到列表                cart_skus.append({
'id': sku.id, 'name': sku.name, 'count': count, 'default_image_url': sku.default_image.url, }) return JsonResponse({
'code': 0, 'errmsg': 'ok', 'cart_skus': cart_skus}) else: # 如果用户不存在就去cookie中取出购物车数据 cart_cookie = request.COOKIES.get('cart') # 解码 cart_cookie_data = pickle.loads(base64.b64decode(cart_cookie)) # 遍历商品id sku_id_list = cart_cookie_data.keys() for sku_id in sku_id_list: count = cart_cookie_data[sku_id]['count'] sku = SKU.objects.get(id=int(sku_id)) # 组织数据添加到列表 cart_skus.append({
'id': sku.id, 'name': sku.name, 'count': count, 'default_image_url': sku.default_image.url, }) return JsonResponse({
'code': 0, 'errmsg': 'ok', 'cart_skus': cart_skus})

合并cookie中的购物车数据到redis

在用户未登录的时候购物车数据存在cookie中,用户登录之后把cookie中的数据合并到redis中

在QQ登录、登录、注册之后自动登录的时候调用合并的方法

代码

def merge_cart_cookie_to_redis(request, user, response):    """    用户登录合并cookie中的购物车数据到redis    :param request: 请求体    :param user: 用户对象    :param response: 响应体    :return: 返回响应体    """    # 取出cookie中的购物车数据    cart_cookie = request.COOKIES.get('cart')    # 解码    cookie_cart_dict = pickle.loads(base64.b64decode(cart_cookie))    # 如果没有cookie直接返回响应    if not cookie_cart_dict:        return response    # 组织新字典来存放购物车数据    new_cart_dict = {
} # 被选中的商品id列表 new_cart_selected_add = [] # 没有被选中的商品id列表 new_cart_selected_rm = [] # 遍历cookie购物车数据存放到新字典 for sku_id, count_sel in cookie_cart_dict.items(): new_cart_dict[sku_id] = count_sel['count'] # 如果选中了就添加到add列表 没有被选中就添加到rm列表 if count_sel['selected']: new_cart_selected_add.append(sku_id) else: new_cart_selected_rm.append(sku_id) # 连接redis redis_conn = get_redis_connection('carts') # 创建管道 pl = redis_conn.pipeline() # 把cookie中的购物车数据添加到redis中 pl.hmset('cart_%s' % user.id, new_cart_dict) # 选中数据中添加被选中的商品 if new_cart_selected_add: pl.sadd('selected_%s' % user.id, *new_cart_selected_add) # 选中数据中删除没有被选中的商品 if new_cart_selected_rm: pl.srem('selected_%s' % user.id, *new_cart_selected_rm) # 提交操作 pl.execute() # 删除cookie中的购物车数据 response.delete_cookie('cart') # 返回响应 return response

转载地址:http://nquhf.baihongyu.com/

你可能感兴趣的文章
Tomcat 7优化前及优化后的性能对比
查看>>
Java Guava中的函数式编程讲解
查看>>
Eclipse Memory Analyzer 使用技巧
查看>>
tomcat连接超时
查看>>
谈谈编程思想
查看>>
iOS MapKit导航及地理转码辅助类
查看>>
检测iOS的网络可用性并打开网络设置
查看>>
简单封装FMDB操作sqlite的模板
查看>>
iOS开发中Instruments的用法
查看>>
强引用 软引用 弱引用 虚引用
查看>>
数据类型 java转换
查看>>
"NetworkError: 400 Bad Request - http://172.16.47.117:8088/rhip/**/####t/approval?date=976
查看>>
mybatis 根据 数据库表 自动生成 实体
查看>>
C结构体、C++结构体、C++类的区别
查看>>
进程和线程的概念、区别和联系
查看>>
CMake 入门实战
查看>>
绑定CPU逻辑核心的利器——taskset
查看>>
Linux下perf性能测试火焰图只显示函数地址不显示函数名的问题
查看>>
c结构体、c++结构体和c++类的区别以及错误纠正
查看>>
Linux下查看根目录各文件内存占用情况
查看>>