购物车与结算接口

购物车中心

用户点击价格策略加入购物车,个人中心可以查看自己所有购物车中数据~~

在购物车中可以删除课程,还可以更新购物车中课程的价格策略~~~

所以接口应该有四种请求方式, get,post,patch,delete~~

我们在做这个功能之前,首先要讨论我们购物车中数据存在哪~~~为什么要这么存~~

因为购物车是属于中间状态数据~~而且很多时候需要过期时间~~所以我们选择redis~~

读取速度快~并且redis可以做持久化~~支持的数据类型也比较多~~

然后我们需要讨论~我们存redis~~存什么样的数据结构~对于我们实现需求来说更加方便~

下面看代码中存入redis中的数据结构是什么样的~~

from rest_framework.views import APIView
from rest_framework.response import Response
from utils.authentication import MyAuth
from utils.redis_pool import POOL
from utils.base_response import BaseResponse
import redis
from couse import models
import json, datetime
from utils.exceptions import CommonException
from django.core.exceptions import ObjectDoesNotExist

SHOPPING_CAR_KEY = "shopping_car_%s_%s"  # 购物车在redis的key
ACCOUNT_KEY = "account_%s_%s"  # 支付时候用的key
REDIS_CONN = redis.Redis(connection_pool=POOL)


SHOPPING_CAR_KEY = "shopping_car_%s_%s"  # 购物车在redis的key
ACCOUNT_KEY = "account_%s_%s"  # 支付时候用的key
REDIS_CONN = redis.Redis(connection_pool=POOL)


# shopping_car_ %s_ %s: {
#     id: 1,
#     title: CMDB,
#     course_img: xxxxx,
#     price_policy_dict: {
#         1: {"valid_period_text":有效期1个月,"price": 99}
#       },
#     default_price_policy_id: 3
#
# }    redis库中对应的数据解构(根据查看luffy官网购物车获得)

class ShoppingCar(APIView):
    # 加入购物车必学确认登录(根据token)
    # 添加登录的认证类
    authentication_classes = [MyAuth, ]

    def post(self, request):
        res = BaseResponse()
        try:
            # 1 获取前端传过来的course_id 以及price_policy_id user_id
            course_id = request.data.get("course_id", "")
            price_policy_id = request.data.get("price_policy_id", "")
            user_id = request.user.id
            # 2 验证数据的合法性
            # 2.1 验证course_id是否合法
            course_obj = models.Course.objects.filter(id=course_id).first()
            if not course_obj:
                res.code = 1031
                res.error = "课程不存在"
                return Response(res.dict)
            # 2.2 验证价格策略是否合法
            # 该课程的所有价格策略对象
            price_policy_queryset = course_obj.price_policy.all()

            # 循环获得每个价格策略的详细信息
            price_policy_dict = {}
            for price_policy_obj in price_policy_queryset:
                price_policy_dict[price_policy_obj.id] = {
                    "valid_period_text": price_policy_obj.get_valid_period_display(),
                    "price": price_policy_obj.price
                }
            # 判断价格策略是否在价格策略的字典里

            if price_policy_id not in price_policy_dict:
                res.code = 1032
                res.error = "价格策略不存在"
                return Response(res.dict)
            # 3 构建我们想要的数据结构
            course_info = {
                "id": course_id,
                "title": course_obj.title,
                "course_img": str(course_obj.course_img),
                "price_policy_dict": json.dumps(price_policy_dict, ensure_ascii=False),
                "default_policy_id": price_policy_id
            }

            # 4 写入redis
            # 4.1 先拼接购物车的key
            shopping_car_key = SHOPPING_CAR_KEY % (user_id, course_id)
            # 4.2 写入redis
            print(shopping_car_key, course_info)
            REDIS_CONN.hmset(shopping_car_key, course_info)
            res.data = "加入购物车成功"
        except Exception as e:
            print(str(e))
            # raise
            res.code = 1030
            res.error = "加入购物车失败"
        return Response(res.dict)

    def get(self, request):
        res = BaseResponse()
        try:
            # 1 取到user_id
            user_id = request.user.id
            # 2 拼接购物车的key
            shopping_car_key = SHOPPING_CAR_KEY % (user_id, "*")
            # shopping_car_1_*
            # shopping_car_1_asdgnlaksdj
            # 3 去redis读取该用户的所有加入购物车的课程
            # 3.1 先去模糊匹配出所有符合要求的key
            all_key = REDIS_CONN.scan_iter(shopping_car_key)

            # 3.2 循环所有的keys  得到每个key
            shopping_car_lsit = []
            for key in all_key:
                course_info = REDIS_CONN.hgetall(key)
                course_info["price_policy_dict"] = json.loads(course_info["price_policy_dict"])
                shopping_car_lsit.append(course_info)
            res.data = shopping_car_lsit
        except Exception as e:
            res.code = 1033
            res.error = "加载购物车失败"
        return Response(res.dict)

    def put(self, request):
        res = BaseResponse()

        try:
            # 1 获取前端传过来的course_id 以及price_policy_id
            course_id = request.data.get("course_id", "")
            price_policy_id = request.data.get("price_policy_id", "")
            user_id = request.user.id
            # 校验数据的合法性
            # 2.1 校验course_id是否合法
            shoping_car_key = SHOPPING_CAR_KEY % (user_id, course_id)
            if not REDIS_CONN.exists(shoping_car_key):  # 如果不存在
                res.code = 1035
                res.error = "课程不存在"
                return Response(res.dict)
            # 2.2 判断价格策略是否合法
            course_info = REDIS_CONN.hgetall(shoping_car_key)
            price_policy_dict = json.loads(course_info["price_policy_dict"])
            if str(price_policy_id) not in price_policy_dict:
                res.code = 1036
                res.error = "所选的价格策略不存在"
                return Response(res.dict)
            # 修改信息写入redis
            REDIS_CONN.hmset(shoping_car_key, course_info)
            res.data = "更新成功"
        except Exception as e:
            # raise
            res.code = 1034
            res.error = "更新价格策略失败"
        return Response(res.dict)

    def delete(self, request):
        res = BaseResponse()

        try:
            # 获取前端传过来的course_id
            course_id = request.data.get("course_id", "")
            user_id = request.user.id
            # 判断课程id是否合法
            shopping_car_key = SHOPPING_CAR_KEY % (user_id, course_id)
            if not REDIS_CONN.exists(shopping_car_key):
                res.code = 1039
                res.error = "删除的课程不存在"
                return Response(res.dict)
            # 删除redis中的数据
            REDIS_CONN.delete(shopping_car_key)
        except Exception as e:
            print(str(e))
            res.code = 1037
            res.error = "删除失败"
        return Response(res.dict)


class AccountView(APIView):
    """
    结算接口
                shopping_car_ 1_ 1: {
                id: 1,
                title: CMDB,
                course_img: xxxxx,
                price_policy_dict: {
                    1: {有效期1个月, 99}
                  },
                default_price_policy_id: 3
            }

            account_%s_%s:{
                "course_info":{
                                    id: 1,
                                    title: CMDB,
                                    course_img: xxxxx,
                                    price_policy_dict: {
                                        1: {有效期1个月, 99}
                                      },
                                    default_price_policy_id: 3
                                },
                "coupons":{
                       1:{},
                       3:{},
                }
            }
            global_coupon_1:{}
    """
    authentication_classes = [MyAuth, ]

    def post(self, request, *args, **kwargs):
        # 获取数据
        user = request.user
        course_id_list = request.data.get("course_id_list", "")
        print(course_id_list)
        response = BaseResponse()
        try:

            # 清空操作
            # 找到当前用户所有以account_userid_ *  全部清空
            del_list = REDIS_CONN.keys(ACCOUNT_KEY % (user.pk, "*"))
            print(del_list)
            REDIS_CONN.delete(*del_list)

            # 2 创建数据结构

            for course_id in course_id_list:
                account_key = ACCOUNT_KEY % (user.pk, course_id)
                account_dict = {}
                shopping_car_key = SHOPPING_CAR_KEY % (user.pk, course_id)

                # 判断课程是否存在在购物车中
                if not REDIS_CONN.exists(shopping_car_key):
                    raise CommonException("购物车不存在该课程", 1040)

                # 将课程信息加入到没有一个课程结算字典中
                course_info = REDIS_CONN.hgetall(shopping_car_key)  # 从redis中获取课程信息
                account_dict["course_info"] = course_info

                # 将课程优惠券加入结算每一个课程结算字典中

                # 查询当前用户拥有未使用的,在有效期的企鹅与当前课程相关的优惠券
                account_dict["course_coupons"] = self.get_coupon_dict(request, course_id)

                # 将课程优惠券加入结算每一个课程结算字典中get_coupon_dict

                # 存储结算信息
                REDIS_CONN.set(account_key, json.dumps(account_dict))

            # 获取通用优惠券,加入redis中
            REDIS_CONN.set("global_coupon_%s" % user.pk, json.dumps(self.get_coupon_dict(request)))

        except CommonException as e:
            response.code = e.code
            response.error = e.msg
        except Exception as e:
            response.code = 500
            response.error = str(e)

        return Response(response.dict)

    def get_coupon_dict(self, request, course_id=None):

        now = datetime.datetime.utcnow()

        coupon_record_list = models.CouponRecord.objects.filter(
            user=request.user,
            status=0,
            coupon__valid_begin_date__lte=now,
            coupon__valid_end_date__gt=now,
            coupon__content_type_id=10,
            coupon__object_id=course_id

        )

        coupon_dict = {}
        for coupon_record in coupon_record_list:
            coupon_dict[coupon_record.pk] = {
                "name": coupon_record.coupon.name,  # 名字
                "coupon_type": coupon_record.coupon.get_coupon_type_display(),  # 券类型
                "money_equivalent_value": coupon_record.coupon.money_equivalent_value,  # 等值货币
                "off_percent": coupon_record.coupon.off_percent,  # 折扣百分比
                "minimum_consume": coupon_record.coupon.minimum_consume,  # 最低消费
                "valid_begin_date": coupon_record.coupon.valid_begin_date.strftime("%Y-%m-%d"),  # 有效期开始时间
                "valid_end_date": coupon_record.coupon.valid_end_date.strftime("%Y-%m-%d"),  # 有效结束时间
            }
        print(coupon_dict)
        return coupon_dict

    def get(self, request):
        pass
视图

 

posted @ 2018-11-28 19:51  洛丶丶丶  阅读(972)  评论(0编辑  收藏  举报