Django ManyToManyField和Form

时间:2018-11-16 15:38:33

标签: python django forms

我正在写我的第一个Django App,我的models.py文件中有两个类,Ingredient和Meal。食物有很多成分,您假设可以设置餐点中每种成分的量,所以这就是我的models.py

class Ingredient(models.Model):
    name = models.CharField(max_length=200)

class Meal(models.Model):
    name = models.CharField(max_length=200)
    ingredients = models.ManyToManyField(Ingredient, through='Recipe_Ingredient')

class Recipe_Ingredient(models.Model):
    recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE)
    ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
    quantity = models.FloatField()
    UNITY_CHOICES = (
        ('g', 'Gram(s)'),
        ('kg', 'Kilogram(s)'),
        ('l', 'Liter(s)'),
        ('cl', 'Centiliter(s)'),
    )

    quantityUnit = models.CharField(
        max_length=2,
        choices=UNITY_CHOICES,
        default='g',
)

Recipe_Ingrent类是用于存储数量的ManyToMany关联表。

这里的问题是,在这种情况下,我不知道如何使用表单。我有一个模板meal_edit.html,它在form.py中调用django表单。

要添加成分,我的表单很简单,就像这样:

from .models import Ingredient

class IngridientForm(forms.ModelForm):
    class Meta:
        model = Ingredient
        fields = ('name',)

那么,我应该如何制作一个可以创建包含多种成分和每种成分数量的配方的表格?

1 个答案:

答案 0 :(得分:0)

Django formsets:

从本质上讲,每种成分都是较大表单中的一种表单(尽管模板中将只有一个<form标签。例如:

models.py:

class Ingredient(models.Model):
    name = models.CharField(max_length=200)

class Meal(models.Model):
    name = models.CharField(max_length=200)

class Recipe_Ingredient(models.Model):
    meal = models.ForeignKey(Meal, on_delete=models.CASCADE)
    recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE) # Not sure what this is, but I'll leave that to you
    ingredient = models.ForeignKey(Ingredient, on_delete=models.CASCADE)
    quantity = models.FloatField()
    UNITY_CHOICES = (
        ('g', 'Gram(s)'),
        ('kg', 'Kilogram(s)'),
        ('l', 'Liter(s)'),
        ('cl', 'Centiliter(s)'),
    )

    quantityUnit = models.CharField(
        max_length=2,
        choices=UNITY_CHOICES,
        default='g',
    )

forms.py:

from django import forms
from your_app import models

class IngredientForm(forms.ModelForm):

    class Meta:
        model = models.Recipe_Ingredient
        fields = ['ingredient', 'quantity', 'quantityUnit']


IngredientFormset = forms.inlineformset_factory(models.Meal, models.Recipe_Ingredient, form=IngredientForm, extra=2)

views.py:

from your_app import forms, models

class YourMealModelView():

    model = models.Meal

    def get_context_data(self, *args, **kwargs):
        context_data = super().get_context_data(**kwargs)

        if self.request.method == 'POST':
            context_data['ingredients_formset'] = forms.IngredientFormset(
                self.request.POST,
                instance=self.object,   # as in your Meal object
                prefix='ingredients'
            )
        else:
            context_data['ingredients_formset'] = forms.IngredientFormset(
                instance=self.object, prefix='ingredients'
            )

    def form_valid(self, form):
        # You can manipulate the formsets here as well:
        context_data = self.get_context_data()
        ingredients_formset = context_data['ingredients_formset']

        meal = form.save()

        for i_form in ingredients_formset:
            delete = i_form.cleaned_data.get('DELETE')
            if delete:
                i_form.instance.delete()
                continue

            # do stuff and save
            ingredient_recipe = i_form.save(commit=False)
            ingredient_recipe.meal = meal
            ingredient_recipe.save()

模板:

<form id="meal_form">
    {% for field in form.fields %}
        {{ field.label }}
        {{ field }}
    {% endfor %}

    <table>
        <thead>
            {{ ingredients_formset.management_form }}
            <tr>
                <th>Ingredient</th>
                <th>Quantity</th>
                <th>Units</th>
                <th>Delete?</th>
            </tr>
        </thead>
        <tbody>
            {% for i_form in ingredients_formset.forms %}
                <tr id="{{ i_form.prefix }}">
                    {{ i_form.id }}
                    <td>{{ i_form.ingredient }}</td>
                    <td>{{ i_form.quantity }}</td>
                    <td>{{ i_form.quantityUnit }}</td>
                    <td>{% if i_form.instance.pk %}{{i_form.DELETE %}{% endif %}</td>
                </tr>
            {% endfor %}
         </tbody>
    </table>
</form>

当然,我还有很多遗漏的东西,例如使用javascript向表单集中添加新项目,如何处理新餐vs编辑现有餐,使用什么Django View等,但这给了您一个主意。