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

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

Django rest framework post data not being serialized properly

问题

I have 2 models

class MenuItem(models.Model):
    title = models.CharField(max_length=255, db_index=True)
    price = models.DecimalField(max_digits=6, decimal_places=2, db_index=True)
    featured = models.BooleanField(db_index=True)
    category = models.ForeignKey(Category, on_delete=models.PROTECT)
    def __str__(self):
        return f'{self.title}';

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, default=0)
    price = models.DecimalField(max_digits=6, decimal_places=2, default=0)

    class Meta:
        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:

class MenuItemSerializer(serializers.HyperlinkedModelSerializer):
    title = serializers.CharField(max_length=255)
    price = serializers.DecimalField(max_digits=6, decimal_places=2)
    category_id = serializers.IntegerField(write_only=True)
    category = CategorySerializer(read_only=True)
    featured = serializers.BooleanField()    
    class Meta:
        model = MenuItem
        fields = ['title', 'price', 'category', 'category_id', 'featured']
        depth = 1

class CartSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault(),
    )
    menu_item = MenuItemSerializer
    quantity = serializers.IntegerField()
    # unit_price = serializers.DecimalField(max_digits=6, decimal_places=2, style={'input_type':'hidden'})
    unit_price = serializers.ReadOnlyField(source="menuitem.price", read_only=True)
    price = SerializerMethodField()
    class Meta:
        model = Cart
        fields = ['user', 'menuitem', 'unit_price', 'quantity', 'price']

    def get_price(self, obj):
        return obj.quantity * obj.unit_price

and then the relevant view

class Cart(mixins.ListModelMixin,
           mixins.DestroyModelMixin,
           generics.GenericAPIView):
    queryset = Cart.objects.all()
    serializer_class = CartSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    
    def post(self, request, *args, **kwargs):
        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
}
英文:

I have 2 models

class MenuItem(models.Model):
    title = models.CharField(max_length=255, db_index=True)
    price = models.DecimalField(max_digits=6, decimal_places=2, db_index=True)
    featured = models.BooleanField(db_index=True)
    category = models.ForeignKey(Category, on_delete=models.PROTECT)
    def __str__(self):
        return f'{self.title}'

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, default=0)
    price = models.DecimalField(max_digits=6, decimal_places=2, default=0)

    class Meta:
        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:

class MenuItemSerializer(serializers.HyperlinkedModelSerializer):
    title = serializers.CharField(max_length=255)
    price = serializers.DecimalField(max_digits=6, decimal_places=2)
    category_id = serializers.IntegerField(write_only=True)
    category = CategorySerializer(read_only=True)
    featured = serializers.BooleanField()    
    class Meta:
        model = MenuItem
        fields = ['title', 'price', 'category', 'category_id', 'featured']
        depth = 1

class CartSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault(),
    )
    menu_item = MenuItemSerializer
    quantity = serializers.IntegerField()
    # unit_price = serializers.DecimalField(max_digits=6, decimal_places=2, style={'input_type':'hidden'})
    unit_price = serializers.ReadOnlyField(source="menuitem.price", read_only=True)
    price = SerializerMethodField()
    class Meta:
        model = Cart
        fields = ['user', 'menuitem', 'unit_price', 'quantity', 'price']

    def get_price(self, obj):
        return obj.quantity * obj.unit_price

and then the relevant view

class Cart(mixins.ListModelMixin,
           mixins.DestroyModelMixin,
           generics.GenericAPIView):
    queryset = Cart.objects.all()
    serializer_class = CartSerializer

    def get(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)
    
    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
    
    def post(self, request, *args, **kwargs):
        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方法如下:

def get_price(self, obj):
    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:

def get_price(self, obj):
    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:

确定