Лучший метод Django для нескольких записей для одного поля

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

При создании нового рецепта мне нужно иметь возможность добавить несколько экземпляров ингредиента, единицы измерения, значения единицы измерения. Например:

ingredient = Lemon
measurement_unit = ml
unit_value = 100

Затем мне нужно добавить еще один ингредиент и проделать то же самое. После этого я смогу сохранить рецепт.

Какой метод лучше всего использовать для достижения этой цели?

Я бы создал модель для Ingredient и затем установил отношения "многие ко многим" между ингредиентами и рецептами.

Похожие:

class Ingredient(models.Model):

   name = models.CharField(max_length=150, unique=True)
   measurement_unit = models.CharField(max_length=150, unique=True)
   unit_value = models.IntegerField()
   recipe = models.ManyToManyField(Recipe)

Тогда из любого рецепта можно было бы получить доступ ко всем ингредиентам.

Не знаю, как насчет лучшего, но очевидный вариант - это модель RecipeIngredient

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

class Recipe( models.Model):
    name = models.CharField( ...)
    status = models.CharField( choices = STATUS_CHOICES, ...)
    ...

class Ingredient( models.Model):
    name = models.CharField( unique=True, ...)

    ...

class RecipeIngredient( models.Model):
    recipe = models.ForeignKey( Recipe, models.PROTECT, related_name='ingredients', ...)
    ingredient = models.ForeignKey( Ingredient, models.PROTECT, ...)
    unit = models.CharField( choices=UNIT_CHOICES, ...)
    value = models.FloatField( ...)

использование:

recipe = Recipe( name = 'Lemon Cheesecake', status=Recipe.ON_HOLD )
recipe.save()
# ON_HOLD stops anybody using a recipe only half populated with ingredients

ingredient = Ingredient.objects.get( name='lemon juice')
item = RecipeIngredient(  
    ingredient=ingredient, 
    recipe = recipe,
    unit='ml', 
    value=100 )
item.save()

# repeat until all the ingredients are attached to the recipe
# and other stuff such as instructions are also filled in

recipe.status = Recipe.READY
recipe.save()
# now it's ready for somebody to try to cook it!

Чтобы получить список:

recipe = Recipe.objects.get( name = 'Lemon Cheesecake')
for item in recipe.ingerdients.all():
    item.ingredient.field ... # refers to data in the related Ingredient
    item.unit
    item.value

Похоже на проект Foodgram от YP:)) В моей Foodgram я использовал through опцию для ManyToManyField и я думаю, что это оптимально. https://docs.djangoproject.com/en/4.0/ref/models/fields/#django.db.models.ManyToManyField.through. Это четко объяснено в документации django. Вы можете написать что-то вроде этого:

class Recipe(models.Model):
    name = models.CharField(...)
    ...
    ingredients = models.ManyToManyField(
        Ingredient,
        through=RecipeIngredient,
        ...
    )

class Ingredient(models.Model):
    name = models.CharField(...)
    measurement_unit = models.CharField(...)
    ...

class RecipeIngredient(models.Model):
    ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
    recipe = models.ForeignKey(
        Recipe,
        related_name='recipeingredients',
        on_delete=models.CASCADE
    )
    amount = models.FloatField()
Вернуться на верх