• Django REST framework+Vue 打造生鲜电商项目(笔记七)


    十、购物车、订单管理和支付功能

    1、添加商品到购物车

    (1)trade/serializer.py

    这里的serializer不继承ModelSerializer,是因为自己写的Serializer更加灵活,因为购物车在添加相同数据的时候,是不能报错的,而如果继承ModelSerializer ,在model.py的ShoppingCart里面需要定义unique_together,这在mixins.CreateModelMixin里的create方法的is_valid的时候,如果记录里面已经有添加记录了,在验证的时候就报错了,根本不会用到ModelSerializer 里面的create方法,这时就算我们重写ModelSerializer的create方法也是无效的。当然也可以重写mixins.CreateModelMixin里的create方法,但这样我们就不能用Serializer给我们的好处。

    from .models import ShoppingCart
    from rest_framework import serializers
    from goods.models import Goods
    
    class ShopCartSerializer(serializers.Serializer):
        #获取当前登录的用户
        user = serializers.HiddenField(
            default=serializers.CurrentUserDefault()
        )
        nums = serializers.IntegerField(required=True, label="数量",min_value=1,
                                        error_messages={
                                            "min_value":"商品数量不能小于一",
                                            "required": "请选择购买数量"
                                        })
        #这里是继承Serializer,必须指定queryset对象,如果继承ModelSerializer则不需要指定(ModelSerializer是goods = GoodsSerializer())
        #goods是一个外键,可以通过这方法获取goods object中所有的值
        goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())
    
        #继承的Serializer没有create功能,必须写一个create方法
        def create(self, validated_data):
            # validated_data是已经处理过的数据
            # 获取当前用户
            # view中:self.request.user;serizlizer中:self.context["request"].user 重点
            user = self.context["request"].user
            nums = validated_data["nums"]
            goods = validated_data["goods"]
    
            existed = ShoppingCart.objects.filter(user=user, goods=goods)
            #如果购物车中有记录,数量+1
            #如果购物车车没有记录,就创建
            if existed:
                existed = existed[0]
                existed.nums += nums
                existed.save()
            else:
                #添加到购物车
                existed = ShoppingCart.objects.create(**validated_data)
    
            return existed
    # 上面整个流程的总结概述就是,首先在view里面,调用get_serializer(data=request.data),获取ShopCartSerializer,把数据填入其中,进行is_valid()验证,这一步就是判断user(能不能获取当前用户)和nums
    # (传入的值符不符合要求)。通过之后,调用perform_create(),然后运行里面的serializer.save(),.save()方法去调用我们继承的serializers.Serializer里面的create()方法,在这里也就是我们重写的那个,
    # 然后就是进行各种判断,把数据保存到数据库啥的,最后把数据返回。

    (2)trade/views.py

    # trade/views.py
    
    from rest_framework import viewsets
    from rest_framework.permissions import IsAuthenticated
    from utils.permissions import IsOwnerOrReadOnly
    from rest_framework_jwt.authentication import JSONWebTokenAuthentication
    from rest_framework.authentication import SessionAuthentication
    from .serializers import ShopCartSerializer
    from .models import ShoppingCart
    
    class ShoppingCartViewset(viewsets.ModelViewSet):
        """
        购物车功能
        list:
            获取购物车详情
        create:
            加入购物车
        delete:
            删除购物记录
        """
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    
        serializer_class = ShopCartSerializer
    
        def get_queryset(self):
            return ShoppingCart.objects.filter(user=self.request.user)

    (3)配置url

    # 配置购物车的url
    router.register(r'shopcarts', ShoppingCartViewset, base_name="shopcarts")

     2、添加购物车数量

    根据商品id搜索收藏记录在view中添加

    lookup_field = "goods_id"

    对购物车商品进行update操作,发现出错

    是因为Serializer继承BaseSerializer,但是Serializer中并没有重载update方法,而BaseSerializer中的方法只会报错。所有添加一个update方法。这点跟Modelserializer不同,那里面已经写好了update方法。

    trade/serializer.py

    def update(self, instance, validated_data):
            # 修改商品数量
            instance.nums = validated_data["nums"]
            instance.save()
            return instance

     3、vue和购物车接口联调

    购物车中可以看商品详情,需要写一个商品详情的serializer,所有在view中需要动态设置serializer

    (1)trade/serializer.py

    class ShopCartDetailSerializer(serializers.ModelSerializer):
        """
        购物车详情
        """
        # goods在ShoppingCart里面是个外键
        # 因为由ShopCartSerializer的create知道,一个ShopCart记录对应一个商品
        # 所以many=False。这个想了好久才发现T_T
        goods = GoodsSerializer(many=False, read_only=True)
    
        class Meta:
            model = ShoppingCart
            fields = "__all__"

    (2)trade/views.py

    需要动态选择serializer

        def get_serializer_class(self):
            if self.action == "list":
                return ShopCartDetailSerializer
            else:
                return ShopCartSerializer

    4、订单管理接口

    (1)trade/serializer.py

    用户添加商品到购物车,点去购物车结算,填上地址留言,结算生成订单,在会员中心我的订单里面,可以看到订单列表,点订单可以看到订单的详细信息。

    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) def generate_order_sn(self): # 当前时间+userid+随机数 from random import Random ramdon_ins = 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=ramdon_ins.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__"

    (2)trade/views.py

    class OrderViewset(mixins.ListModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin,
                       viewsets.GenericViewSet):
        """
        订单管理
        list:
            获取个人订单
        delete:
            删除订单
        create:
            新增订单
        """
        permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
        authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
        serializer_class = OrderSerializer
    
        def get_queryset(self):
            return OrderInfo.objects.filter(user=self.request.user)
    
        # create之后还有两步,在获取了订单的序列之后,首先需要把购物车的内容添加到订单号里,还有一个是
        # 将它们删除
        def perform_create(self, serializer):
            order = serializer.save()
         # 获取购物车所有商品 shop_carts
    = ShoppingCart.objects.filter(user=self.request.user) for shop_cart in shop_carts: order_goods = OrderGoods() order_goods.goods = shop_cart.goods order_goods.goods_num = shop_cart.nums order_goods.order = order order_goods.save() # 清空购物车 shop_cart.delete() return order

    (3)配置url

    # 配置订单的url
    router.register(r'orders', OrderViewset, base_name="orders")

    为了展示订单的详细信息,需要写一个OrderDetailSerializer

    trade/serializer.py

    # 订单中的商品
    class OrderGoodsSerializier(serializers.ModelSerializer):
        goods = GoodsSerializer(many=False)
    
        class Meta:
            model = OrderGoods
            fields = "__all__"
    
    
    # 订单商品的详细信息
    # goods字段需要嵌套一个OrderGoodsSerializer
    class OrderDetailSerializer(serializers.ModelSerializer):
        goods = OrderGoodsSerializier(many=True) # 这里容易犯的错误就是会用GoodsSerializer,但从models里面知道,ForeignKey OrderInfo
    # 的是order字段,所以
    related_name="goods"是在order字段里面的。 这样OrderInfo
                               # 通过"goods"反向指向OrderGoods,然后写一个关于OredrGoods的Serializer就行。
      class Meta:
        model
    = OrderInfo
        fields
    = "__all__"
  • 相关阅读:
    Maven 查看jar包的间接依赖
    Maven 下载一个 jar 包 及其它所有依赖的jar 到本地
    maven 自动构建 web 工程模板命令
    Linux Centos系统中设置定时重启
    (转)关于Android中为什么主线程不会因为Looper.loop()里的死循环卡死?引发的思考,事实可能不是一个 epoll 那么 简单。
    Linux中设置系统时间和时区
    版本管理工具svn(转)
    #pragma预处理命令
    插入排序
    选择排序
  • 原文地址:https://www.cnblogs.com/linyuhong/p/9945225.html
Copyright © 2020-2023  润新知