Django. Получение данных из Queryset

Есть книга рецептов, в которой перечислены компоненты рецепта и их процентное соотношение. Нужен функционал в виде формы, в которую пользователь вводи число - размер партии, и на выходе получает рецепт на заданный размер партии.

models.py

class Recipe(models.Model):
    recipe_name = models.CharField(max_length=200, verbose_name='Название рецепта')
    mass = models.FloatField(default=0, verbose_name='Общая масса')
    category = models.ForeignKey(Category, on_delete=models.CASCADE, default=0)

    def save(self, *args, **kwargs):
        ings = self.ingredient_set.all()
        for ing in ings:
            ing.concentration = ing.mass / self.mass
            ing.save()
        return super(Recipe, self).save(*args, **kwargs)

    def __str__(self):
        return self.recipe_name



class Ingredient(models.Model):
    recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, related_name="ingredient_set")
    ingredient = models.CharField('Ингредиент',max_length=200)
    mass = models.FloatField('Масса', default=0)
    concentration = models.FloatField('Концентрация',default=-1)

    def __str__(self):
        return self.ingredient

    def save(self, *args, **kwargs):
        if not self.pk:
            self.recipe.mass += self.mass
            self.recipe.save()
        else:
            prev_mass = Ingredient.objects.get(pk=self.pk).mass
            if prev_mass != self.mass:
                self.recipe.mass += self.mass - prev_mass
                self.recipe.save()
        self.concentration = (self.mass / self.recipe.mass) * 100

        return super(Ingredient, self).save(*args, **kwargs)

    def delete(self, *args, **kwargs):
        self.recipe.mass -= self.mass
        self.recipe.save()
        return super(Ingredient, self).delete(*args, **kwargs)

views.py

def batch(request, pk):
    recipe_id = Recipe.objects.get(pk=pk)
    recipe = recipe_id.ingredient_set.values()
    batch_size = request.POST.get('batch_size')
    if request.method == 'POST':
        form = RecipeBatchForm(request.POST)
        if form.is_valid():

                batch = recipe.ingredient.concentration/100*batch_size

        return batch
    else:
        form = RecipeBatchForm()

    return render(request, 'recipes/recipe_batch.html', {'form': form, 'batch': batch, 'batch_size': batch_size, 'recipe_id': recipe_id})

Выдает ошибку 'QuerySet' object has no attribute 'ingredient', хотя в local vars в recipe все нужные мне данные есть - <QuerySet [{'id': 11, 'recipe_id': 2, 'ingredient': 'Вода', 'mass': 37.8, 'concentration': 81.203007518797}, и так же для остальных компонентов.

Как правильно рассчитать batch и вывести его в шаблоне?


Ответы (2 шт):

Автор решения: nanamar
for r in recipe:
    concentration = r['concentration']
→ Ссылка
Автор решения: Константин Комиссаров
  1. В вашем случае, переменная recipe это список объектов. И вы пытаетесь у этого списка вызвать метод ingredient. В примере ингредиент один у рецепта - вода. Но ведь это связь один ко многим и ингредиентов может быть много. Соответственно, вам надо рассчитать размер порции для каждого из них.

  2. У вас неудачные названия переменных. В recipe_id у вас никакой не id, а целый Recipe. В recipe у вас не Recipe, а список словарей из полей ингредиентов. В объекте Ingredient есть поле ingredient, хотя граздо лучше было бы назвать его name, чтобы не вносить путаницу.

  3. Нет необходимости брать только values от игредиентов.

В общем, примерно так

def batch(request, pk):
    recipe = Recipe.objects.get(pk=pk) # Получаем объект рецепта

    # Перебираем ингредиенты и считаем размер порции для каждого
    batches = []
    for ingredient in recipe.ingredient_set.all(): 
        batch = ingredient.concentration / 100 * batch_size
        batches.append({ingredient.id: batch})

Пример условный, т.к. не знаю точно ваших задач.

→ Ссылка