Как добавить дополнительные поля в сериализатор модели в django ModelViewSet?
Классы сериализатора корзины
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 в классе CartItemsViewSet
@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)
Модель корзины
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')
Я хочу реализовать добавление пользователем пункта меню в корзину. Но проблема в том, что я не добавляю дополнительное поле 'user_id' При сохранении таблицы с помощью сериализатора было показано следующее сообщение об ошибке. { «user_id": [ «Это поле обязательно для заполнения». ] }
Причина, по которой drf выдает эту ошибку, даже если вы передаете user.id
в метод save
, заключается в ошибке, вызванной методом is_valid
, который выполняется перед методом save
, а ключ user
не установлен в request.data
.
Для передачи сериализатору зарегистрированного пользователя вы можете использовать это поле сериализатора:
user = serializers.HiddenField(default=serializers.CurrentUserDefault())
Это поле само получит пользователя из запроса.
Подсказка: Я думаю, вам следует пересмотреть вашу модель и уникальные ограничения (особенно ограничения в сериализаторе)
Подсказка: HTTP-код статуса для отказа в аутентификации - 401, или если вы хотите вернуть код статуса 403, сообщение должно быть каким-то другим, например permission denied
user_id
должен быть только для чтения, иначе он ожидает найти данные в запросе, так что:
class CartSerializer(serializers.ModelSerializer):
# …
user_id = serializers.IntegerField(read_only=True)
# …
Вы записываете user_id
через .save()
сериализатор:
serializer.save(user_id=user.id)