【问题标题】:An other way to manage Django Model instance from ModelChoiceField in formset从表单集中的 ModelChoiceField 管理 Django 模型实例的另一种方法
【发布时间】:2018-11-05 08:04:42
【问题描述】:

我不确定这是否可能。我正在尝试使用 Django (2.0) Form 和 Formset 在一个视图上。这是我的模型:

from uuid import uuid4

class Aliment(models.Model):
    id = models.CharField(max_length=36, primary_key=True, unique=True, default=uuid4, editable=False)
    libelle = models.CharField(max_length=50)
    def __str__(self):
        return self.libelle

class Menu(models.Model):
    id = models.CharField(max_length=36, primary_key=True, unique=True, default=uuid4, editable=False)
    libelle = models.CharField(max_length=50)
    aliments = models.ManyToManyField(Aliment, through='Ingredient')
    def __str__(self):
        return self.libelle

class Ingredient(models.Model):
    id = models.CharField(max_length=36, primary_key=True, unique=True, default=uuid4, editable=False)
    aliment = models.ForeignKey(Aliment, on_delete=models.CASCADE)
    menu = models.ForeignKey(Menu, on_delete=models.CASCADE)
    quantite = models.IntegerField(default=0)
    def __str__(self):
        return "({0}:{1})".format(self.quantite, self.aliment)

我正在使用Formset 处理来自Ingredient 的('aliment', 'quantite')。这是我的表格:

class MenuModelForm(forms.ModelForm):
    class Meta:
        model = Menu
        fields = ['libelle',]

class IngredientModelForm(forms.ModelForm):
    class Meta:
        model = Ingredient
        fields = ['aliment', 'quantite',]

主要目的是,Menu 有几个Aliment 到Ingredient 类。 使用 javascript,我将 Aliment 项目从一个列表 (list1) 动态添加到 Menu.Ingredient 列表 (list2)。

用户在 list2 中添加项目的唯一方法是单击 list1 的某个“添加按钮”。

问题是ModelChoiceField 带有包含数据库中所有Aliment 实例的选择。

我会为每个Ingredient 管理一种元组('aliment.id', 'aliment.libelle', 'quantite') 属于Menu 实例。

一方面,我可以在我的Ingredient formset 模板中显示,如下所示:

<table>
    {% for item in menu.ingredient %}
        <tr>
            <td>
                <p name="{{ item.aliment.html_name }}" id="{{ fs.aliment.id_for_label }}"
                value="{{ item.aliment.id }}">{{ fs.aliment.libelle }}</p>
            </td>
            <td><input type="number" name="{{ item.quantite.html_name }}" value="{{ item.quantite.value }}" id="{{ item.quantite.id_for_label }}" /></td>
        </tr>
    {% endfor %}
</table>

另一方面,获取Aliment 实例的Ingredient formset 迭代的方法是什么?

我不知道 Django Form 和 Django 哲学是不是为此而生的。

请给点建议。

谢谢!

【问题讨论】:

    标签: django python-3.x django-forms formsets


    【解决方案1】:

    我意识到我在提问时很困惑。我会试着去 下次再简洁一点。

    无论如何,我找到了许多问题的解决方案(也许你会明白我的意思:p)。

    我将libelle 字段添加到我的IngredientModelForm,如下所示:

    class IngredientModelForm(forms.ModelForm):
    
        def __init__(self, *args, **kwargs):
            super().__init__(*args, **kwargs)
            print(kwargs['instance'])
            self.fields['libelle'].initial = kwargs['instance'].aliment.libelle
    
        class Meta:
            model = Ingredient
            fields = ['aliment', 'quantite',]
    
        libelle = forms.CharField(max_length=50)
    

    所以我可以访问模板中的libelle 字段。
    在我的视图文件中,我这样做了:

    def add_menu(request):
        ingredientFormSet = modelformset_factory(Ingredient, form=IngredientModelForm, fields=('aliment', 'quantite'), extra=0)
        if request.method == 'POST':
            form = MenuForm(request.POST)
            formset = ingredientFormSet(request.POST)
            if form.is_valid() and formset.is_valid():
                ...
        else:
            menu = Menu.objects.all()[0]
            form = MenuModelForm(instance=menu)
            formset = ingredientFormSet(queryset=menu.ingredient_set.all())
    

    因此对于每个IngredientModelForm 实例,其libelle 字段的初始值将是该值 附加到Ingredient 的Aliment 实例。

    我们来看看模板:

    <form action="" method="POST">
        {{ formset.management_form }}
        <ul>
            {% for fs in formset.forms %}
            <li>
            {{ fs.id.label_from_instance }}
                <span><input type="hidden" name="{{ fs.id.html_name }}" value="{{ fs.id.value }}" id="{{ fs.id.id_for_label }}" /></span>
                <span><input type="hidden" name="{{ fs.aliment.html_name }}" value="{{ fs.aliment.value }}" id="{{ fs.aliment.id_for_label }}" /></span>
                <span>{{ fs.libelle.value }}<input type="hidden" name="{{ fs.libelle.html_name }}" value="{{ fs.libelle.value }}" id="{{ fs.libelle.id_for_label }}" /></span>
                <span><input type="number" name="{{ fs.quantite.html_name }}" value="{{ fs.quantite.value }}" id="{{ fs.quantite.id_for_label }}" /></span>
            </li>
            {% endfor %}
        </ul>
        <input type="submit" value="Ajouter" />
    </form>
    

    所以,我可以用select widget 显示Aliment 的名称(因为我的Aliment 选项由另一个列表管理)。

    我不知道这对 Django 是否是一个好习惯。

    请随意提出其他简单的解决方案! :)

    【讨论】:

      猜你喜欢
      • 2023-03-28
      • 1970-01-01
      • 1970-01-01
      • 2018-02-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-28
      • 1970-01-01
      相关资源
      最近更新 更多