(生鲜项目_支付板块)22. 添加购物车+修改购物车数量

第一步: 添加购物车

1.购物车应该具备的功能

  • 如果该商品已经存在, 那么添加购物车时, 其数量加一, 否则新增一个商品
  • 设置多个接口以分别完成: 减少商品数量, 增加商品数量, 删除商品
  • 很明显第2个功能可以使用一个接口来完成, 这就是mixin的增删改查功能

2.首先我们需要在ShoppingCart的model里添加一个 unique_together = ("user","goods") , 这时因为一个用户只能对同一件商品添加一次购物车, 之后仅仅是num字段的增减

3.假设使用ModelSerializer, 假设前端此刻再post已存在的(user,goods), 当我们一旦调用 CreateModelMixin, 那么其内部方法中的create就会自动执行serializer.is_valid,  所以在这一步就报错了, 我们就没法对num执行加减的操作了

4.基于以上考虑, 我们必须使用Serializer来灵活的对(user,goods)这种情况进行操作, 这样才能实现num字典的增减操作

5.需要注意的是goods字段为外键, 所以这里要用到serializer的  PrimaryKeyRelatedField  字段, 注意其必须添加一个queryset 属性

6.validated_data里面究竟有没有user字段?

(生鲜项目_支付板块)22. 添加购物车+修改购物车数量_第1张图片

 从这里来看,validated_data里面有user字段,所以这里就不清楚视频为何要单独取 user = self.context["request"].user

 7.这里总结一下form或者serializer, 其实他们都只有2个作用:

  • 一是对前端post过来的参数一一校验(前提是参数名和serializer的字段名要一致, 然后在createModeMixin时,会自动调用is_valid(),来校验参数合法性)
    • validator属性, 局部钩子, 全局钩子等都可以实现更加复杂的过滤
  • 二是返回数据, 如果使用serializer, 那么默认是返回自己定义的所有的字段, 如果是ModelSerializer,那么可以通过fields来指定返回哪些字段

8. 代码

serializer.py

from rest_framework import serializers

from goods.models import Goods
from .models import ShoppingCart


class ShopCartSerializer(serializers.Serializer):
    # 获取当前用户,并隐藏user字段
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    nums = serializers.IntegerField(required=True, min_value=1, label="数量",
                                    error_messages={
                                        "required": "请选择购买数量",
                                        "min_value": "商品数量不能小于1"
                                    })
    # 如果是外键,需要使用PrimaryKeyRelatedField,且需要加上queryset属性指明对象来源
    goods = serializers.PrimaryKeyRelatedField(required=True, label="商品",
                                               queryset=Goods.objects.all())

    # 使用Serializer来完成某一个字段的更新逻辑时,必须重写create方法,并手动进行save
    # validated_data是校验过后的数据, initial_data是校验之前的数据
    def create(self, validated_data):
        # 在serializer里,request封装在self.context里面
        user = self.context["request"].user
        nums = validated_data["nums"]
        goods = validated_data["goods"]

        # 添加到购物车有2种方式,一是该商品已存在,二是该商品不存在,这里需要区分对待
        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

    class Meta:
        fields = ("nums",)

viewset

from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication

from utils.permissions import IsOwnerOrReadOnly
from .serializers import ShopCartSerializer
from .models import ShoppingCart


class ShoppingCartViewset(viewsets.ModelViewSet):
    """
    购物车功能
    list:
        获取购物车详情
    create:
        加入购物车
    delete:
        删除购物车
    update:
        更新购物车
    """
    queryset = ShoppingCart.objects.all()
    serializer_class = ShopCartSerializer
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)

ur

# 购物车接口()
router.register(r'shopcarts', ShoppingCartViewset, basename="shopcarts")

9. 测试

(生鲜项目_支付板块)22. 添加购物车+修改购物车数量_第2张图片

 

 

第二步: 修改购物车数量

1.使用serializer来处理POST和PUT请求时, 需要自己重写create和update, (delete方法不用重写), 否则报错如下:

 

    # 接收到update请求时,必须自己重写
    def update(self, instance, validated_data):
        instance.nums = validated_data["nums"]
        instance.save()
        return instance

 

(生鲜项目_支付板块)22. 添加购物车+修改购物车数量_第3张图片

 

 (生鲜项目_支付板块)22. 添加购物车+修改购物车数量_第4张图片

 2. 我们希望shopcarts接口的id为goods的id, 而不是shopcarts表格本身的id序号,

lookup_field = "goods_id"

 (生鲜项目_支付板块)22. 添加购物车+修改购物车数量_第5张图片(生鲜项目_支付板块)22. 添加购物车+修改购物车数量_第6张图片

 3.只返回当前用户的购物车

    # 只返回当前用户的购物车
    def get_queryset(self):
        return ShoppingCart.objects.filter(user=self.request.user)

 

 

第三步: Vue联调

1.上面我们完成了对购物车POST请求的返回, 实际上前端页面中还需要对购物车接口执行get请求, 以获取购物车详情, 所以我们还需要一个serializer, 来应付get请求,即重写get_serializer_class

2.代码

serializer

# 购物车接口(处理get请求)
class ShopCartDetailSerializer(serializers.ModelSerializer):
    goods = GoodsSerializer(many=False)  # 一定要注意many属性,这里一个shopcart对应一个goods,所以为false

    class Meta:
        model = ShoppingCart
        fields = "__all__"

 

view

    # list请求需要单独的包含goods详情页的serializer来应付
    def get_serializer_class(self):
        if self.action == "list":
            return ShopCartDetailSerializer
        else:
            return ShopCartSerializer

 

3.Vue联调

(生鲜项目_支付板块)22. 添加购物车+修改购物车数量_第7张图片

 

 

 

 

 

 

 

 

 

 

 

---  君子处其实,不处其华;治其内,不治其外   张居正  ----

你可能感兴趣的:((生鲜项目_支付板块)22. 添加购物车+修改购物车数量)