How to add additional fields in model serializer in django ModelViewSet?

Cart Serializer classs

class CartSerializer(serializers.ModelSerializer):
    user = UserSerializer(read_only=True)
    menuitem = MenuItemSerializer(read_only=True)
    price = serializers.SerializerMethodField(method_name='calculate_price')
    menuitem_id = serializers.IntegerField(write_only=True)
    user_id = serializers.IntegerField(write_only=True)

    class Meta:
        model = Cart
        fields = ['id', 'user', 'menuitem', 'quantity',
                  'unit_price', 'price', 'menuitem_id', 'user_id']
        validators = [
            validators.UniqueTogetherValidator(
                queryset=MenuItem.objects.all(),
                fields=('id',),
                message="Menuitem should be unique in this curt"
            ),
            validators.UniqueTogetherValidator(
                queryset=User.objects.all(), fields=('id'), message="User should be unique")
        ]

    def calculate_price(self, item: Cart):
        print(item.unit_price * item.quantity)
        return item.unit_price * item.quantity

add_cart method in CartItemsViewSet class

 @action(detail=True, methods=['post'])
    def add_cart(self, request, pk=None):
        if request.user.is_authenticated:
            user = request.user
        else:
            return Response('User is not authenticated', 403)
        # print(request.data)
        # print(request.user.id)
        # user_id = user.id
        # menuitem_id = request.data['menuitem_id']
        # quantity = request.data['quantity']
        # unit_price = request.data['unit_price']
        # id = request.data['id']
        # pack_data = {'user_id': user_id, 'menuitem_id': menuitem_id,
        #              'quantity': quantity, 'unit_price': unit_price, 'id': id}

        serializer = serializers.CartSerializer(
            data=request.data)

        if serializer.is_valid(raise_exception=True):
            print(serializer.validated_data)
            serializer.save(user_id=user.id)
            return Response('Item is added successfully.', 201)

Cart Model

class Cart(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    menuitem = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
    quantity = models.SmallIntegerField(),
    unit_price = models.DecimalField(max_digits=6, decimal_places=2)
    price = models.DecimalField(max_digits=6, decimal_places=2)

    class Meta:
        unique_together = ('menuitem', 'user')

I want to implement a login user add a menu item to their cart. But the problem is that I do not add additional field 'user_id' when save the table with the serializer the following error message has been shown. { "user_id": [ "This field is required." ] }

Error message

The reason the drf raises that error, even though you pass the user.id to the save method, is the error raised by method is_valid that is run before the save method and the key user is not set in request.data.

To pass the logged-in user to the serializer you can use this serializer field:

user = serializers.HiddenField(default=serializers.CurrentUserDefault())

This field will get the user from the request by itself.

Hint: I think you should revise your model and unique constraints (especially constraints in serializer) Hint: The HTTP status code for not authentication is 401 or if you want to return status code 403 the message should be something else e.g. permission denied

user_id should be read-only, otherwise it expects to find the data in the request, so:

class CartSerializer(serializers.ModelSerializer):
    # …
    user_id = serializers.IntegerField(read_only=True)
    # …

You write the user_id through the .save() of the serializer:

serializer.save(user_id=user.id)
Вернуться на верх