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." ] }
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)