python test development django-rest-framework-93. UniqueTogetherValidator joint unique verification of deserialization (ModelSerializer)…

Foreword

When adding a product earlier, the product code can only be added once and can be verified with a unique field using the UniqueValidator. If a user collects a product, one user can collect multiple products, and one product can also be collected by multiple people.
However, the same person can only collect the same product once, so you can use UniqueTogetherValidator to jointly uniquely verify

Collection product

Add products and collect products models.py model design

from django.db import models
from django.contrib.auth.models import User
# Create your models here.
# Author-Shanghai Youyou QQ communication group: 717225969
# blog address https://www.cnblogs.com/yoyoketang/


class Goods(models.Model):
    """Product List"""
    goods_name = models.CharField(max_length=30,
                                  default="",
                                  verbose_name="product name")
    goods_code = models.CharField(max_length=30,
                                  unique=True,
                                  verbose_name="Product code")
    merchant_id = models.CharField(max_length=30,
                                   default="",
                                   blank=True, null=True,
                                   verbose_name="merchant ID")
    merchant_name = models.CharField(max_length=30,
                                     default="",
                                     blank=True, null=True,
                                     verbose_name="merchant name")
    # goods_price = models.FloatField(blank=True, null=True,
    # default=0,
    # verbose_name="Product price")
    goods_price = models.DecimalField(max_digits=10, decimal_places=2,
                                      blank=True, null=True,
                                      default=0, verbose_name="product price")
    goods_stock = models.IntegerField(blank=True, null=True,
                                      default=0,
                                      verbose_name="item inventory")
    goods_groupid = models.IntegerField(blank=True, null=True,
                                        default=0,
                                        verbose_name="Product group")
    goods_status = models.IntegerField(choices=(
                                                (0, 'Removed'),
                                                (1, 'For Sale')
                                               ),
                                       default=1,
                                       verbose_name="0 off the shelves 1 on sale")

    price = models.FloatField(blank=True, null=True,
                              default=0,
                              verbose_name="cost price")

    create_time = models.DateTimeField(auto_now_add=True, verbose_name="Add Time")
    update_time = models.DateTimeField(auto_now=True, verbose_name="Modification time")

    class Meta:
        verbose_name_plural = 'commodity'
        verbose_name = "Product information"

    def __str__(self):
        return self.goods_code


class UserCollect(models.Model):
    """User Favorites"""
    user = models.ForeignKey(User, on_delete=models.CASCADE, verbose_name="userid")
    goods = models.ForeignKey(Goods, on_delete=models.CASCADE, verbose_name="goods", help_text="goods id")
    status = models.CharField(choices=(
                                        (0, 'Cancel favorite'),
                                        (1, 'Collected')
                                       ),
                              default=1,
                              verbose_name="0 Uncollect 1 Collect")
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="Add Time")
    update_time = models.DateTimeField(auto_now=True, verbose_name="Modification time")

    class Meta:
        verbose_name = 'User Collection'
        verbose_name_plural = verbose_name
        # Unique combination, a product can only be collected once
        unique_together = ("user", "goods")

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

Serialized Collection Product

During serialization, the user field is a hidden field and does not need to be passed by the user. As long as the user is logged in, he can obtain the currently logged in account through request.user.
status has 2 statuses, which do not need to be passed in by the user. Set read_only=True
validators.UniqueTogetherValidator jointly verifies the uniqueness of ‘user’, ‘goods’ fields
This validator can be used unique_together to impose constraints on model instances. It has two required parameters and an optional messages parameter:

  • queryset required – This is the queryset against which uniqueness should be enforced.
  • fields Required – A list or tuple of field names that should form a unique set. These must exist as fields in the serializer class.
  • message – The error message that should be used when validation fails.
from .models import Goods, UserCollect
from rest_framework import validators
# Author-Shanghai Youyou QQ communication group: 717225969
# blog address https://www.cnblogs.com/yoyoketang/


class UserCollectSerializer(serializers.ModelSerializer):
    # Get the currently logged in user
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    status = serializers.ChoiceField(choices=(
                                                (0, 'Cancel favorite'),
                                                (1, 'Collected')
                                               ),
                                           read_only=True)

    def to_representation(self, instance):
        """return of to_representation custom serialized data"""
        data = super().to_representation(instance)
        data.update(status=instance.get_status_display())
        return data

    class Meta:
        # validate achieves unique union, a product can only be collected once
        validators = [
            validators.UniqueTogetherValidator(
                queryset=UserCollect.objects.all(),
                fields=('user', 'goods'),
                #The message information can be customized
                message="Collected"
            )
        ]
        model = UserCollect
        # You need to return the product ID when collecting, because you must know the product ID when canceling collection.
        fields = '__all__' # Return all fields

Add views to favorites and queries

# Author-Shanghai Youyou QQ communication group: 717225969
# blog address https://www.cnblogs.com/yoyoketang/


class UserCollectAPIView(APIView):
    """my collection"""

    def get(self, request, *args, **kwargs):
        """Check my collection"""
        collect = UserCollect.objects.all().filter(status=1, user=request.user) # Query your own collection
        serializer = UserCollectSerializer(instance=collect, many=True, context={"request": request})

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

    def post(self, request, *args, **kwargs):
        """Add to Favorites"""
        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": "Illegal parameter",
                "data": verify_data.errors
            })

Test my collection function

When collecting products, just pass the product ID

If it has been collected, it will prompt that it has been collected

When querying, each user only queries his own data with status 1