Django REST框架无法正确序列化POST数据。

huangapple go评论143阅读模式
英文:

Django rest framework post data not being serialized properly

问题

I have 2 models

  1. class MenuItem(models.Model):
  2. title = models.CharField(max_length=255, db_index=True)
  3. price = models.DecimalField(max_digits=6, decimal_places=2, db_index=True)
  4. featured = models.BooleanField(db_index=True)
  5. category = models.ForeignKey(Category, on_delete=models.PROTECT)
  6. def __str__(self):
  7. return f'{self.title}';
  8. class Cart(models.Model):
  9. user = models.ForeignKey(User, on_delete=models.CASCADE)
  10. menuitem = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
  11. quantity = models.SmallIntegerField()
  12. unit_price = models.DecimalField(max_digits=6, decimal_places=2, default=0)
  13. price = models.DecimalField(max_digits=6, decimal_places=2, default=0)
  14. class Meta:
  15. unique_together = ('menuitem', 'user')

The MenuItem.price should be equal to Cart.unit_price for a particular object. Now the problem I'm having is writing the serializer for the Cart Model.

So far I've tried this:

  1. class MenuItemSerializer(serializers.HyperlinkedModelSerializer):
  2. title = serializers.CharField(max_length=255)
  3. price = serializers.DecimalField(max_digits=6, decimal_places=2)
  4. category_id = serializers.IntegerField(write_only=True)
  5. category = CategorySerializer(read_only=True)
  6. featured = serializers.BooleanField()
  7. class Meta:
  8. model = MenuItem
  9. fields = ['title', 'price', 'category', 'category_id', 'featured']
  10. depth = 1
  11. class CartSerializer(serializers.ModelSerializer):
  12. user = serializers.HiddenField(
  13. default=serializers.CurrentUserDefault(),
  14. )
  15. menu_item = MenuItemSerializer
  16. quantity = serializers.IntegerField()
  17. # unit_price = serializers.DecimalField(max_digits=6, decimal_places=2, style={'input_type':'hidden'})
  18. unit_price = serializers.ReadOnlyField(source="menuitem.price", read_only=True)
  19. price = SerializerMethodField()
  20. class Meta:
  21. model = Cart
  22. fields = ['user', 'menuitem', 'unit_price', 'quantity', 'price']
  23. def get_price(self, obj):
  24. return obj.quantity * obj.unit_price

and then the relevant view

  1. class Cart(mixins.ListModelMixin,
  2. mixins.DestroyModelMixin,
  3. generics.GenericAPIView):
  4. queryset = Cart.objects.all()
  5. serializer_class = CartSerializer
  6. def get(self, request, *args, **kwargs):
  7. return self.list(request, *args, **kwargs)
  8. def create(self, request, *args, **kwargs):
  9. serializer = self.get_serializer(data=request.data)
  10. serializer.is_valid(raise_exception=True)
  11. serializer.save()
  12. return Response(serializer.data, status=status.HTTP_201_CREATED)
  13. def post(self, request, *args, **kwargs):
  14. return self.create(request, *args, **kwargs)

However, this does not return the required value for price. It only returns 0.

I'm a Django newbie, and this has been driving me nuts. It would be nice if someone could help out.

This is an example response that I'm getting:

  1. {
  2. "menuitem": 1,
  3. "unit_price": 2.5,
  4. "quantity": 3,
  5. "price": 0
  6. }
英文:

I have 2 models

  1. class MenuItem(models.Model):
  2. title = models.CharField(max_length=255, db_index=True)
  3. price = models.DecimalField(max_digits=6, decimal_places=2, db_index=True)
  4. featured = models.BooleanField(db_index=True)
  5. category = models.ForeignKey(Category, on_delete=models.PROTECT)
  6. def __str__(self):
  7. return f'{self.title}'
  8. class Cart(models.Model):
  9. user = models.ForeignKey(User, on_delete=models.CASCADE)
  10. menuitem = models.ForeignKey(MenuItem, on_delete=models.CASCADE)
  11. quantity = models.SmallIntegerField()
  12. unit_price = models.DecimalField(max_digits=6, decimal_places=2, default=0)
  13. price = models.DecimalField(max_digits=6, decimal_places=2, default=0)
  14. class Meta:
  15. unique_together = ('menuitem', 'user')

The MenuItem.price should be equal to Cart.unit_price for a particular object. Now the problem I'm having is writing the serializer for the Cart Model.

So far I've tried this:

  1. class MenuItemSerializer(serializers.HyperlinkedModelSerializer):
  2. title = serializers.CharField(max_length=255)
  3. price = serializers.DecimalField(max_digits=6, decimal_places=2)
  4. category_id = serializers.IntegerField(write_only=True)
  5. category = CategorySerializer(read_only=True)
  6. featured = serializers.BooleanField()
  7. class Meta:
  8. model = MenuItem
  9. fields = ['title', 'price', 'category', 'category_id', 'featured']
  10. depth = 1
  11. class CartSerializer(serializers.ModelSerializer):
  12. user = serializers.HiddenField(
  13. default=serializers.CurrentUserDefault(),
  14. )
  15. menu_item = MenuItemSerializer
  16. quantity = serializers.IntegerField()
  17. # unit_price = serializers.DecimalField(max_digits=6, decimal_places=2, style={'input_type':'hidden'})
  18. unit_price = serializers.ReadOnlyField(source="menuitem.price", read_only=True)
  19. price = SerializerMethodField()
  20. class Meta:
  21. model = Cart
  22. fields = ['user', 'menuitem', 'unit_price', 'quantity', 'price']
  23. def get_price(self, obj):
  24. return obj.quantity * obj.unit_price

and then the relevant view

  1. class Cart(mixins.ListModelMixin,
  2. mixins.DestroyModelMixin,
  3. generics.GenericAPIView):
  4. queryset = Cart.objects.all()
  5. serializer_class = CartSerializer
  6. def get(self, request, *args, **kwargs):
  7. return self.list(request, *args, **kwargs)
  8. def create(self, request, *args, **kwargs):
  9. serializer = self.get_serializer(data=request.data)
  10. serializer.is_valid(raise_exception=True)
  11. serializer.save()
  12. return Response(serializer.data, status=status.HTTP_201_CREATED)
  13. def post(self, request, *args, **kwargs):
  14. return self.create(request, *args, **kwargs)

However this does not return the required value for price. It only returns 0.

I'm a django newbie and this has been driving me nuts. It would be nice if someone could help out.

This is an example response that I'm getting:
{
"menuitem": 1,
"unit_price": 2.5,
"quantity": 3,
"price": 0
}

答案1

得分: 0

你在Cart模型中存储了priceunit_price,以及MenuItem模型。

CartSerializer中,在get_price方法内,你使用Cartunit_price来计算最终价格,而不是使用MenuItemunit_price,而CartSerializerunit_price字段具有source="menuitem.price"

因此,在你分享的响应中,你从菜单项模型中得到了"unit_price": 2.5,而你的价格是通过使用Cart模型的unit_price字段计算的,这个字段必须是0,因为它的默认值是0。因此,你的最终价格计算结果为3(数量)* 0(来自Cart模型的价格)= 0,而它应该是3(数量)* 2.5(来自MenuItem模型的价格)= 7.5。

确保从Cart模型中删除多余的字段,以减少混淆,并更新CartSerializer中的get_price方法如下:

  1. def get_price(self, obj):
  2. return obj.quantity * obj.menuitem.price
英文:

You are storing price and unit_price in the Cart model along with the MenuItem model.

In the CartSerializer, inside the get_price method, you are computing the final price by using the unit_price of the Cart, not the MenuItem, while the unit_price field of the CartSerializer has source="menuitem.price".

So in the response you shared, you are getting "unit_price": 2.5 from the menu item model, while your price is being calculated by using the unit_price field of Cart model, which must be 0, as it defaults to 0. Hence, your final price results in 3 (quantity) * 0 (price from Cart model) = 0, while it should be 3 (quantity) * 2.5 (price from MenuItem model) = 7.5.

Make sure that you remove redundant fields from the Cart model so it is less confusing, and update the get_price method in the CartSerializer to:

  1. def get_price(self, obj):
  2. return obj.quantity * obj.menuitem.price

huangapple
  • 本文由 发表于 2023年6月1日 00:55:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76375782.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定