zoukankan      html  css  js  c++  java
  • 【Vue+DRF 生鲜电商】购物车和订单管理(七)

    1. 购物车

    接口:http://127.0.0.1:8000/shopcarts/

    需求:

    • 添加商品到购物车
    • 购物车中所有商品信息(详情)
    • 删除购物车记录

    1.1 添加商品到购物车

    1、trade/seriliazers.py

    class ShopCartSerializer(serializers.Serializer):
        """购物车"""
        # 获取当前登录用户
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()
        )
        nums = serializers.IntegerField(required=True, label='数量', min_value=1,
                                        error_messages={
                                            'min_value': '商品数量不能小于一',
                                            'required': '请选择购买数量'
                                        })
        # 外键,获取 goods 中所有值,必须指定 queryset,继承 ModelSerializer 无需指定
        goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())
        add_time = serializers.DateTimeField(read_only=True, format="%Y-%m-%d %H:%M")
    
        def create(self, validated_data):
            """
            serializers.Serializer 没有 save() 需要重写 create
            :param validated_data:已处理过的数据(前端提交的数据)
            :return:
            """
            # 获取当前用户
            user = self.context['request'].user
            nums = validated_data['nums']
            goods = validated_data['goods']
    
            # 查询数据库,若有记录(表示添加到购物车,该商品),数量 + nums,否则就添加到购物车
            existed = ShoppingCart.objects.filter(user=user, goods=goods)
    
            # 数量增加
            if existed:
                existed = existed[0]
                existed.nums += nums
                existed.save()
            else:
                # 添加到购物车
                existed = ShoppingCart.objects.create(**validated_data)
    
            return existed
    
        def update(self, instance, validated_data):
            """更新购物车,修改数量"""
            instance.nums = validated_data['nums']
            instance.save()
            return instance
    

    这里之所以采用继承 Serializer 而不是 ModelSerializer,是因为 ModelSerializer 的 creat() 方法会之前创建一条新的记录,当用户将同一商品多次添加到购物车时应该只需数量变化,而不是重写创建一条新的购物车记录,所以需要重写 create() 方法。

    2、trade/views.py

    class ShoppingCartViewSet(viewsets.ModelViewSet):
        """
        购物车功能:
        list:获取购物车详情
        create:加入购物车
        delete:删除购物车记录
        """
        serializer_class = ShopCartSerializer
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    
        # 商品 ID,用于购物车更新(update() 商品数量)
        lookup_field = "goods_id"
    
        def get_queryset(self):
            """获取当前用户购物车列表"""
            return ShoppingCart.objects.filter(user=self.request.user)
    

    3、配置路由 MxShop/urls.py

    router.register(r'shopcarts', ShoppingCartViewSet, basename='shopcarts')  # 购物车
    

    1.2 获取购物车商品详情

    接口:

    # 获取所有商品信息:get
    http://127.0.0.1:8000/shopcarts/
    
    # 单独获取某个商品详情:get
    http://127.0.0.1:8000/shopcarts/1/
    

    1、trade/serializers.py

    class ShopCartDetailSerializer(serializers.ModelSerializer):
        """购物车中商品详情"""
        # 一个购物车对应一个商品.
        goods = GoodsSerializer(many=False, required=True)
    
        class Meta:
            model = ShoppingCart
            fields = ('goods', 'nums')
    

    2、trade/views.py

    class ShoppingCartViewSet(viewsets.ModelViewSet):
        ....
        def get_serializer_class(self):
            """动态选择 serializer"""
            if self.action == 'list':
                return ShopCartDetailSerializer
            else:
                return ShopCartSerializer
    

    动态选择 serializer,当添加或删除购物车商品时:ShopCartSerializer,获取购物车商品详情(列表)时:ShopCartDetailSerializer

    2. 订单管理

    接口地址:http://127.0.0.1:8000/orders/

    需求分析:

    • 用户添加商品到购物车,点击结算
    • 填上地址留言(必须),结算(提交)订单
    • 会员中心可查看所以的订单列表,点击单个订单可查看订单详细信息

    支持:创建订单、获取个人订单(列表、详情)、删除订单

    1、trade/serializers.py

    class OrderGoodsSerializer(serializers.ModelSerializer):
        """订单中的商品"""
        goods = GoodsSerializer(many=False)
    
        class Meta:
            model = OrderGoods
            fields = '__all__'
    
    
    class OrderDetailSerializer(serializers.ModelSerializer):
        """
        订单中商品详细信息
        """
        # goods字段需要嵌套一个OrderGoodsSerializer
        goods = OrderGoodsSerializer(many=True)
        add_time = serializers.DateTimeField(read_only=True, format="%Y-%m-%d %H:%M")
    
        class Meta:
            model = OrderInfo
            fields = '__all__'
    
    
    class OrderSerializer(serializers.ModelSerializer):
        """订单"""
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()
        )
    
        # 生成订单时,不需 post以下数据
        pay_status = serializers.CharField(read_only=True)
        trade_no = serializers.CharField(read_only=True)
        order_sn = serializers.CharField(read_only=True)
        pay_time = serializers.DateTimeField(read_only=True)
        nonce_str = serializers.CharField(read_only=True)
        pay_type = serializers.CharField(read_only=True)
    
        add_time = serializers.DateTimeField(read_only=True, format="%Y-%m-%d %H:%M")
    
        def generate_order_sn(self):
            """
            生成订单号:当前时间+userid+随机数
            :return:
            """
            from random import Random
            random_str = Random()
            order_sn = "{time_str}{userid}{ranstr}".format(time_str=time.strftime("%Y%m%d%H%M%S"),
                                                           userid=self.context['request'].user.id,
                                                           ranstr=random_str.randint(10, 99))
            return order_sn
    
        def validate(self, attrs):
            """validate 中添加 order_sn,然后再 view 中就可以 save"""
            attrs['order_sn'] = self.generate_order_sn()
            return attrs
    
        class Meta:
            model = OrderInfo
            fields = '__all__'
    

    三个 serializer

    • OrderGoodsSerializer:订单中商品(OrderGoods
    • OrderDetailSerializer:订单中商品详细信息(OrderInfo
    • OrderSerializer:订单(OrderInfo

    前端 vue 页面中需要提交的信息只有 订单留言、订单金额、收货地址、签收人、联系电话,其他诸如 订单号、支付状态、交易号等不需要在前端提交

    流程:表单字段验证通过后,validate() 中调用 generate_order_sn() 生成订单号,并将其保存到 attrs 字典中,之后 view 视图 save() 保存,订单创建成功。

    2、trade/views.py

    class OrderViewSet(viewsets.GenericViewSet, mixins.CreateModelMixin, mixins.ListModelMixin, mixins.DestroyModelMixin,
                       mixins.RetrieveModelMixin):
        """
        订单相关
        list:获取个人订单
        create:创建订单
        delete:删除订单
        """
        serializer_class = OrderSerializer
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    
        def get_serializer_class(self):
            # 订单详情
            if self.action == 'retrieve':
                return OrderDetailSerializer
            else:
                return OrderSerializer
    
        def perform_create(self, serializer):
            """
            提交订单之前步骤
                1、将购物车中商品保存到 OrderGoods
                2、清空购物车
            :param serializer:
            :return:
            """
            order = serializer.save()
            # 获取购物车中所有商品
            shop_carts = ShoppingCart.objects.filter(user=self.request.user)
            for shop in shop_carts:
                order_goods = OrderGoods()
                order_goods.goods = shop.goods
                order_goods.goods_num = shop.nums
                order_goods.order = order
                order_goods.save()
    
                # 清空购物车
                shop.delete()
    
            return order
    
        def get_queryset(self):
            return OrderInfo.objects.filter(user=self.request.user)
    

    保存之前将购物车中商品保存到 OrderGoods 中,另外就是清空购物车。

    3、配置路由 MxShop/urls.py

    router.register(r'orders', OrderViewSet, basename='orders')  # 订单
    

  • 相关阅读:
    Codeforces461E Appleman and a Game 做题心得
    关于贪心问题的处理
    各种容斥 笔记
    博弈论 笔记
    家庭多个路由器组网方案(AP+AC)
    21.06.06 训练赛
    Redirect...
    Web Api实践系列(三)route特性使用
    《Red Tuner》隐私政策
    前缀和-1915. 最美子字符串的数目
  • 原文地址:https://www.cnblogs.com/midworld/p/13629732.html
Copyright © 2011-2022 走看看