Reputation: 181
I would like sum data from nested object.
My model:
class Diet(models.Model):
day = models.IntegerField()
meals = models.ManyToManyField(Meal)
user = models.ForeignKey(User, on_delete=models.CASCADE)
def __str__(self):
return f'{self.day} - {self.user}'
My viewset:
class DietViewSet(viewsets.ModelViewSet):
queryset = Diet.objects.all()
serializer_class = DietSerializer
pagination_class = None
def get_queryset(self):
if self.action == 'list':
self.queryset = Diet.objects.filter(user=self.request.user).order_by('day')
else:
self.queryset = Diet.objects.all().order_by('day')
return super(DietViewSet, self).get_queryset()
def get_permissions(self):
if self.action in ['list', 'retrieve']:
self.permission_classes = [permissions.AllowAny]
else:
self.permission_classes = [IsDietician]
return super(DietViewSet, self).get_permissions()
My serializers:
class MealSerializer(serializers.ModelSerializer):
class Meta:
model = models.Meal
fields = '__all__'
class DietSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
result = super(DietSerializer, self).to_representation(instance)
result['meals'] = MealSerializer(instance.meals, many=True).data
return result
class Meta:
model = models.Diet
fields = '__all__'
Now I would like add total_kcal
which will be calculate by data from meals.
I tried did it by
kcal = serializers.MethodSerializerField()
and
def get_kcal(self, obj)
but I don't know how can I get data from serialized objects in to_representation.
Example response:
[
{
"id":1,
"day":1,
"user":1,
"meals":[
{
"id":4,
"name":"Rise",
"description":"",
"kcal":150.0,
"protein":3.0,
"fat":0.0,
"carbs":28.0
},
{
"id":5,
"name":"Chocoloate",
"description":"",
"kcal":200.0,
"protein":0.0,
"fat":0.0,
"carbs":100.0
}
]
}
]
Upvotes: 1
Views: 1528
Reputation: 181
Thank you Arakkal Abu but I found additional method to do it ;)
I added to my model:
@property
def total_kcal(self):
qs = self.meals.through.objects.all().aggregate(total_kcal=models.Sum('meal__kcal'))
return qs['total_kcal']
and change fields in DietSerializr to:
fields = ['day', 'type', 'meals', 'user', 'total_kcal']
Upvotes: 1
Reputation: 88569
You can use Python's list comprehension here as
class DietSerializer(serializers.ModelSerializer):
def to_representation(self, instance):
result = super(DietSerializer, self).to_representation(instance)
result['meals'] = MealSerializer(instance.meals, many=True).data
# You can use the list comprehension here as
result["kal_sum"] = sum([meal["kcal"] for meal in result['meals']])
return result
class Meta:
model = models.Diet
fields = '__all__'
Upvotes: 3