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 }
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