Лучший способ добавить несколько полей в эту модель?

В моем проекте Django у меня есть модель для рецепта напитка, которая позволяет вводить до 10 ингредиентов плюс их количество. Мне интересно, возможно ли сделать это более DRY способом, чем я делаю сейчас? Вот модель, которую я использую в настоящее время:

class Recipe(models.Model):
    ingr_name1 = models.CharField(max_length=250, verbose_name='Ingredient')
    ingr_amount1 = models.DecimalField(max_digits=5, decimal_places=1, verbose_name='Amount')
    ingr_name2 = models.CharField(max_length=250, blank=True, null=True, verbose_name='Ingredient')
    ingr_amount2 = models.DecimalField(max_digits=5, decimal_places=1,blank=True, null=True, verbose_name='Amount')
    ingr_name3 = models.CharField(max_length=250,blank=True, null=True, verbose_name='Ingredient')
    ingr_amount3 = models.DecimalField(max_digits=5, decimal_places=1,blank=True, null=True, verbose_name='Amount')
    ingr_name4 = models.CharField(max_length=250,blank=True, null=True, verbose_name='Ingredient')
    ingr_amount4 = models.DecimalField(max_digits=5, decimal_places=1,blank=True, null=True, verbose_name='Amount')
    ingr_name5 = models.CharField(max_length=250,blank=True, null=True, verbose_name='Ingredient')
    ingr_amount5 = models.DecimalField(max_digits=5, decimal_places=1,blank=True, null=True, verbose_name='Amount')
    ingr_name6 = models.CharField(max_length=250,blank=True, null=True, verbose_name='Ingredient')
    ingr_amount6 = models.DecimalField(max_digits=5, decimal_places=1,blank=True, null=True, verbose_name='Amount')
    ingr_name7 = models.CharField(max_length=250,blank=True, null=True, verbose_name='Ingredient')
    ingr_amount7 = models.DecimalField(max_digits=5, decimal_places=1,blank=True, null=True, verbose_name='Amount')
    ingr_name8 = models.CharField(max_length=250,blank=True, null=True, verbose_name='Ingredient')
    ingr_amount8 = models.DecimalField(max_digits=5, decimal_places=1,blank=True, null=True, verbose_name='Amount')
    ingr_name9 = models.CharField(max_length=250,blank=True, null=True, verbose_name='Ingredient')
    ingr_amount9 = models.DecimalField(max_digits=5, decimal_places=1,blank=True, null=True, verbose_name='Amount')
    ingr_name10 = models.CharField(max_length=250,blank=True, null=True, verbose_name='Ingredient')
    ingr_amount10 = models.DecimalField(max_digits=5, decimal_places=1,blank=True, null=True, verbose_name='Amount')
    drink_name = models.CharField(max_length=250,blank=True, null=True, verbose_name='Drink name')
    drink_story = models.TextField()
    drink_picture = ResizedImageField(upload_to='drinks/', null=True, blank=True)

    def __str__(self):
        return self.drink_name

Вы можете подумать об альтернативном поле модели, таком как JSONField или TextField. JSONFields является хорошим вариантом, если вы:

  1. Не знаю, сколько ingr_amounts& ingr_names используется
  2. .
  3. Если вы хотите обрабатывать их вместе. В рамках текущей модели вам придется делать очистку на основе каждого self.ingr, с json-полем вы можете сделать это с одним self.my_json_field.
  4. .

Кроме того, есть и недостатки, особенно при запросе и обновлении json-полей, это может стать сложнее. Поэтому, прежде чем использовать его, пожалуйста, ознакомьтесь с этим, например, JSONField, json query

*Вы также можете, если это соответствует вашим потребностям, создать новую модель с обоими полями и связать ее с другой моделью через ForeignKey

Один из вариантов - сделать Ingredient собственной моделью и добавить его в качестве поля many to many в модель рецепта. Затем, основываясь на этом ответе, вы можете ограничить количество ингредиентов до 10, добавив функцию ingredients_changed() в модель рецепта.

Ниже приведен непроверенный код:

class Ingredient(model.Model):
    name = models.CharField()
    amount = models.CharField()

class Recipe(models.Model):
    ingredients = models.ManyToManyField(Ingredient)

    def ingredients_changed(recipe, **kwargs):
        if kwargs['instance'].ingredients.count() > 10:
            raise ValidationError("You can't assign more than 10 ingredients")
Вернуться на верх