【问题标题】:Django ManyToManyField and FormDjango 多对多字段和表单
【发布时间】:2019-04-19 19:54:57
【问题描述】:

我正在编写我的第一个 Django 应用程序,我的 models.py 文件中有两个类,成分和膳食。一种食物有很多成分,你应该能够设置餐中每种成分的数量,这就是我的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',)

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

【问题讨论】:

  • 您考虑过使用表单集吗?
  • 嗨@Bott0610,这是我的第一个django项目,我不知道formset,但我读到它用于在同一页面上处理多个表单。我相信在我的情况下,我的页面上只需要一个表单,所以 formset 不会有太大帮助,如果我错了,请纠正我。谢谢。
  • 在views.py中为您的模型创建一个UpdateView,您可以使用表单类并指定您的表单,或者您也可以创建表单的实例并将其传递给您的context_data中的模板并激活它使用 form.as_p
  • 嗨@TheodoreHowell,我正在使用form.as_p从成分表中进行操作,我的问题是如何编写表单以创建具有多种成分且每种成分都与数量相关联的餐点。跨度>

标签: python django forms


【解决方案1】:

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 向表单集添加新项目、如何处理新餐点与编辑现有餐点以及使用什么 Django View 等,但这给了你一个想法。

【讨论】:

  • 感谢您的回复,您能准确告诉我视图中发生了什么吗?我真的不明白。
  • @Luc 其中哪方面需要澄清?
猜你喜欢
  • 1970-01-01
  • 2019-08-12
  • 2018-09-30
  • 2011-08-23
  • 2016-12-17
  • 1970-01-01
  • 2011-10-18
  • 2013-04-27
相关资源
最近更新 更多