Search code examples
python-3.xdjango-modelsdjango-rest-frameworkdjango-serializerdjango-related-manager

How to display value of ManytoMany model relation variable on Django Rest Framework


I'm new to django and struggling, I look over google but couldn't find anything that can help.

Here is my model:

from django.db import models
# from django.contrib.auth.models import


class Order(models.Model):

    table_id = models.IntegerField(unique=True)
    meal = models.ManyToManyField('meals')

    # Meal = models.ForeignKey('Meals',on_delete=models.CASCADE)
    @property
    def total_price(self):
        price = self.meal.objects.all().aggregate(total_price=models.Sum('meals__price'))
        return price['total_price']

class Meals(models.Model):
    name = models.CharField(max_length=100)
    price = models.DecimalField(decimal_places=2, max_digits=5)

Here is my serializer.py :

from rest_framework import serializers


from cafe_app import models
class MealSerializer(serializers.ModelSerializer):

    class Meta:
        model = models.Meals
        fields = ['id','name','price',]

class OrderSerializer(serializers.ModelSerializer):

    **meal = MealSerializer(read_only=True,many=True)**
    class Meta:
        model = models.Order
        fields = ['table_id','meal',]

When I comment meal = MealSerializer(read_only=True,many=True) line then it shows input as table_id and meal where meal values are as Meal Object (1), Mean Object (2) ... .

My questions :

  1. How to display meal Object value instead of it as object.
  2. How Can I use total_price method in my view/serializer.
  3. How to see the flow like how it flows from which class to which class call goes and what is type and value of structure that I received.

Thanks.


Solution

    1. How to display meal Object value instead of it as object.

    Use the __str__ method on Meal.

    1. How Can I use total_price method in my view/serializer.

    Define the annotation in your view's queryset, then add the custom field to the serializer. Do not add it to your model unless it's a one-off thing. The way you have it is pretty inefficient as it'll generate many queries for a list view.

    1. How to see the flow like how it flows from which class to which class call goes and what is type and value of structure that I received.

    Use a debugger in an IDE like PyCharm, PDB, or the classic print statements.

    Below are the corrections I've suggested for 1 and 2.

    # models.py
    from django.db import models
    
    class Order(models.Model):
    
        table_id = models.IntegerField(unique=True)
        meal = models.ManyToManyField('meals')
    
    
    class Meals(models.Model):
        name = models.CharField(max_length=100)
        price = models.DecimalField(decimal_places=2, max_digits=5)
    
        def __str__(self):
            # This method defines what the string representation an instance.
            return f'{self.name}: ${self.price}'
    
    
    # serializers.py
    from rest_framework import serializers
    
    
    from cafe_app import models
    class MealSerializer(serializers.ModelSerializer):
    
        class Meta:
            model = models.Meals
            fields = ['id','name','price',]
    
    
    class OrderSerializer(serializers.ModelSerializer):
        total_price = serializers.FloatField(read_only=True)
        meal = MealSerializer(read_only=True,many=True)
        class Meta:
            model = models.Order
            fields = ['table_id','meal', 'total_price']
    
    
    # views.py
    class OrderView(ViewSet): # or View.
    
        queryset = Order.objects.annotate(
            total_price=Sum('meal__price')
        )