python测试开发django-rest-framework-93.反序列化(ModelSerializer)之UniqueTogetherValidator联合唯一校验

前言

前面添加商品,商品code只能添加一次可以用唯一字段校验UniqueValidator,如果用户收藏商品,一个用户可以收藏多个商品,一个商品也可以被多个人收藏。
但是同一个人针对同一个商品,只能收藏一次,于是可以用UniqueTogetherValidator联合唯一校验

收藏商品

添加商品和收藏商品 models.py 模型设计

from django.db import models
from django.contrib.auth.models import User
# Create your models here.
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/


class Goods(models.Model):
    """商品表"""
    goods_name = models.CharField(max_length=30,
                                  default="",
                                  verbose_name="商品名称")
    goods_code = models.CharField(max_length=30,
                                  unique=True,
                                  verbose_name="商品代号")
    merchant_id = models.CharField(max_length=30,
                                   default="",
                                   blank=True, null=True,
                                   verbose_name="商户ID")
    merchant_name = models.CharField(max_length=30,
                                     default="",
                                     blank=True, null=True,
                                     verbose_name="商户名称")
    # goods_price = models.FloatField(blank=True, null=True,
    #                                 default=0,
    #                                 verbose_name="商品价格")
    goods_price = models.DecimalField(max_digits=10, decimal_places=2,
                                      blank=True, null=True,
                                      default=0, verbose_name="商品价格")
    goods_stock = models.IntegerField(blank=True, null=True,
                                      default=0,
                                      verbose_name="商品库存")
    goods_groupid = models.IntegerField(blank=True, null=True,
                                        default=0,
                                        verbose_name="商品分组")
    goods_status = models.IntegerField(choices=(
                                                (0, '下架'),
                                                (1, '出售中')
                                               ),
                                       default=1,
                                       verbose_name="0下架 1出售中")

    price = models.FloatField(blank=True, null=True,
                              default=0,
                              verbose_name="成本价")

    create_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="修改时间")

    class Meta:
        verbose_name_plural = '商品'
        verbose_name = "商品信息"

    def __str__(self):
        return self.goods_code


class UserCollect(models.Model):
    """用户收藏商品"""
    user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="用户id")
    goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name="商品", help_text="商品id")
    status = models.CharField(choices=(
                                        (0, '取消收藏'),
                                        (1, '已收藏')
                                       ),
                              default=1,
                              verbose_name="0取消收藏 1已收藏")
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="修改时间")

    class Meta:
        verbose_name = '用户收藏'
        verbose_name_plural = verbose_name
        # 唯一联合,一个商品只能收藏一次
        unique_together = ("user", "goods")

    def __str__(self):
        return self.user.username

序列化收藏商品

序列化的时候user字段是隐藏字段,不需要用户传过来,用户只要登录了可以通过request.user获取当前登录的账号
status有2个状态,不需要用户传入,设置read_only=True
validators.UniqueTogetherValidator联合校验'user', 'goods'字段的唯一性
该验证器可用于unique_together对模型实例施加约束。它具有两个必需参数和一个可选messages参数:

  • queryset 必需-这是应针对其强制执行唯一性的查询集。
  • fields 必填-字段名称的列表或元组,应组成唯一的集合。这些必须作为字段存在于序列化程序类中。
  • message -验证失败时应使用的错误消息。
from .models import Goods, UserCollect
from rest_framework import validators
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/


class UserCollectSerializer(serializers.ModelSerializer):
    # 获取当前登录的用户
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    status = serializers.ChoiceField(choices=(
                                                (0, '取消收藏'),
                                                (1, '已收藏')
                                               ),
                                           read_only=True)

    def to_representation(self, instance):
        """to_representation自定义序列化数据的返回"""
        data = super().to_representation(instance)
        data.update(status=instance.get_status_display())
        return data

    class Meta:
        # validate实现唯一联合,一个商品只能收藏一次
        validators = [
            validators.UniqueTogetherValidator(
                queryset=UserCollect.objects.all(),
                fields=('user', 'goods'),
                # message的信息可以自定义
                message="已收藏"
            )
        ]
        model = UserCollect
        # 收藏的时候需要返回商品的id,因为取消收藏的时候必须知道商品的id是多少
        fields = '__all__'  # 返回全部的字段

添加收藏和查询的视图

# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/


class UserCollectAPIView(APIView):
    """我的收藏"""

    def get(self, request, *args, **kwargs):
        """查询我的收藏"""
        collect = UserCollect.objects.all().filter(status=1, user=request.user)   # 查询自己的收藏
        serializer = UserCollectSerializer(instance=collect, many=True, context={"request": request})

        return Response({
            "code": 0,
            "msg": "success!",
            "data": serializer.data
        })

    def post(self, request, *args, **kwargs):
        """添加收藏"""
        verify_data = UserCollectSerializer(data=request.data, context={"request": request})
        if verify_data.is_valid():
            save = verify_data.save()
            return Response({
                "code": 0,
                "msg": "success!",
                "data": UserCollectSerializer(instance=save, context={"request": request}).data
            })
        else:
            return Response({
                "code": 10086,
                "msg": "参数不合法",
                "data": verify_data.errors
            })

测试我的收藏功能

收藏商品的时候,传商品id即可

如果已经收藏,会提示已收藏

查询的时候,每个用户只查询自己的,并且状态为1 的数据

原文地址:https://www.cnblogs.com/yoyoketang/p/14352695.html