【Django REST framework电商项目笔记】第10章 购物车, 订单和支付宝支付功能(上)

购物车接口实现

在交易 trade 应用上
在商品详情页点击加入购物车,弹出提示框(去结算、继续购物),右上角会新增商品到购物车
这是从后台取出来的数据,可以显示商品、数量、总价等信息
添加商品,在商品数量上加一,直接更新数量即可

注意shoppingcart 中的返回

	def __str__(self):
		return "%s(%d)".format(self.goods.name, self.nums)

viewset 编写:

class ShoppingCartViewSet(viewsets.ModelViewSet):
    """
    购物车功能
    list:       获取购物车详情
    create:     加入购物车
    delete:     删除购物车
    """
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    serializer_class = ShoppingCartSerializer
    lookup_field = "goods_id"

我们要为我们的viewset准备配套的Serializer,新建Serializers.py

继承 Serializer 而不是 modelSerializer。因为 Serializer 灵活性高

Model中的 unique_together 在商品的收藏关系中也用到过。在收藏中会只允许收藏一次,而我们现在想要的是重复添加时更新数量。

        unique_together = ("user", "goods")

如果我们继承的是 modelSerializer。那么它在create方法会进行is_vaild的验证。这样就无法进入我们自己的重复加1操作。

class ShoppingCartSerializer(serializers.Serializer):
    # serializers.Serializer可以自定义验证
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )

    nums = serializers.IntegerField(required=True, min_value=1,
                                    error_messages={
                                        "min_value": "商品数量不能小于1",
                                        "required": "请选择购买数量"
                                    })

    goods = serializers.PrimaryKeyRelatedField(required=True,
                                               queryset=Goods.objects.all())

goods是Serializer中的外键字段。查询出goods的object中的所有值。
http://www.django-rest-framework.org/api-guide/fields/
可以看到 Serializer 已经为我们提供的这些字段
外键等这些关系型的被放入了
http://www.django-rest-framework.org/api-guide/relations/

文档中使用的是modelSerializer。所以不需要指明queryset,而我们使用的是Serializer,所以我们要指明queryset
Serializer是没有提供save功能的,所以我们要来重写create方法
create方法传入的validated_data是数据已经经过validate之后的数据。

    def create(self, validated_data):
        user = self.context["request"].user
        nums = validated_data["nums"]
        goods = validated_data["goods"]

        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

而initial_data是未经validate处理过的原始值。需要我们自己进行类型转换等。
在view中是可以直接从request中取出用户的,但是在Serializer里面不能直接从request中取。要从 user = self.context[“request”].user

如果存在的话,将这个对象取出,然后num+1,并保存
不存在的话,就根据validate数据创建出shoppingcart对象。然后返回给前端

viewset中配置Serializer,购物车列表页只获取自己的购物车内容

    serializer_class = ShopCartSerializer
    def get_queryset(self):
        return ShoppingCart.objects.filter(user=self.request.user)

配置相关的url

# 配置购物车的路由
router.register(r'shopcarts', ShoppingCartViewSet, base_name="shopcarts")

修改购物车中商品数量

与收藏一样,希望传递 goods_id 过来而不是传递关系的 id。

    lookup_field = "goods_id"

本来默认的lookup_field是这个model的id主键。这样就可以通过商品id拿到。
Serializer继承于baseSerializer。但是Serializer并没有去重写update方法。

modelSerializer实现了update方法。所以我们可以模仿update方法来实现我们的Serializer中的update。

def update(self, instance, validated_data):
        raise_errors_on_nested_writes('update', self, validated_data)
        info = model_meta.get_field_info(instance)

        # Simply set each attribute on the instance, and then save it.
        # Note that unlike `.create()` we don't need to treat many-to-many
        # relationships as being a special case. During updates we already
        # have an instance pk for the relationships to be associated with.
        for attr, value in validated_data.items():
            if attr in info.relations and info.relations[attr].to_many:
                field = getattr(instance, attr)
                field.set(value)
            else:
                setattr(instance, attr, value)
        instance.save()

        return instance

所以这就是我们继承modelSerializer,不需要实现update的原因

我们的 Serializer 加上 update 方法即可

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

动态的设置Serializer

在获取到商品的单价,数量等之前我们还是要获取到商品的详情的。
比如商品的名称,商品的id(跳转详情用)。商品的图片。
我们现在的Serializer里面只有goods的主键id。需要动态的设置Serializer

这个Serializer是一个动态Serializer。一条购物车关系记录对应的只有一个goods

class ShopCartDetailSerializer(serializers.ModelSerializer):
    goods = GoodsSerializer(many=False, read_only=True)
    class Meta:
        model = ShoppingCart
        fields = ("goods", "nums")

然后在views中进行动态的Serializer的选择

    def get_serializer_class(self):
        if self.action == "retrieve":
            return OrderDetailSerializer
        return OrderSerializer

你可能感兴趣的:(Django)