Django суммирование значений из цикла for в шаблоне

Я хочу вывести сумму значений (калорий, белков, углеводов и т. д.) нескольких продуктов в новой таблице, но не представляю, как это сделать в шаблоне django.

Здесь показано, что отображает цикл for

{% for food in meal.foods.all %}
                <div class='table-container'>
                    <table class='food-table'>
                        <thead>
                            <tr>
                                <th>Name</th>
                                <th>Calories</th>
                                <th>Protein</th>
                                <th>Carbs</th>
                                <th>Fat</th>
                                <th>Sugar</th>
                                <th>Sodium</th>
                            </tr>
                        </thead>
                        <tbody>
                            <tr>
                                <td>{{ food.name }}</td>
                                <td>{{ food.calories }}</td>
                                <td>{{ food.protein }}g</td>
                                <td>{{ food.carbs }}g</td>
                                <td>{{ food.fat }}g</td>
                                <td>{{ food.sugar }}g</td>
                                <td>{{ food.sodium }}mg</td>
                            </tr>
                        </tbody>
                    </table>
                </div>
            {% endfor %}

Новая таблица будет выглядеть следующим образом, но в ней будут отображаться только итоговые значения.

Это можно сделать, используя функцию SUM() в SQL через функцию aggregate Sum. Пример использования здесь.

>>> from django.db.models import Sum
>>> from my_app.models import Food, Meal
>>>
>>> Food.objects.values()
<QuerySet [{'id': 1, 'name': 'Fries', 'calories': Decimal('150.00'), 'protein': Decimal('10.00')}, {'id': 2, 'name': 'Burger', 'calories': Decimal('200.00'), 'protein': Decimal('13.00')}, {'id': 3, 'name': 'Celery', 'calories': Decimal('30.00'), 'protein': Decimal('9.00')}, {'id': 4, 'name': 'Coke', 'calories': Decimal('500.00'), 'protein': Decimal('22.00')}]>
>>>
>>> meal = Meal.objects.get(name='Snack')
>>> meal.foods.values()
<QuerySet [{'id': 1, 'name': 'Fries', 'calories': Decimal('150.00'), 'protein': Decimal('10.00')}, {'id': 2, 'name': 'Burger', 'calories': Decimal('200.00'), 'protein': Decimal('13.00')}, {'id': 4, 'name': 'Coke', 'calories': Decimal('500.00'), 'protein': Decimal('22.00')}]>
>>>
>>> meal.foods.aggregate(Sum('calories'), Sum('protein'))
{'calories__sum': Decimal('850'), 'protein__sum': Decimal('45')}

Затем вы можете просто передать результат dict в ваш шаблон для просмотра.

Если с едой произойдут изменения, это отразится на звонке aggregate.

>>> Food.objects.create(name='Chips', calories=80, protein=5)
<Food: Food object (5)>
>>> meal.foods.add(Food.objects.get(name='Chips'))
>>> meal.foods.aggregate(Sum('calories'), Sum('protein'))
{'calories__sum': Decimal('930'), 'protein__sum': Decimal('50')}

Как я понимаю, вы хотите получить общее количество протеинов, крабов, ... из конкретного блюда.

Простым способом достижения этого было бы создание новых property в моделях Meal.

class Meal(models.Model):
    ...

    @property
    def get_total_protein(self):
        return sum([food.protien for food in self.foods.all()])

    @property
    def get_total_carbs(self):
        return sum([food.carbs for food in self.foods.all()])
    
    # and the same for fat, sugr..

затем вы можете получить доступ к ним в вашем шаблоне. например, давайте обратимся к ним в table foot

<tfoot>
    <tr>
        <th></th>
        <th></th>
        <th>{{ meal.get_total_proteins }}</th>
        <th>{{ meal.get_total_carbs }}</th>
        <th> ... </th>
        <th> ... </th>
        <th> ... </th>
    </tr>
</tfoot>
Вернуться на верх