You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django inlineformset无法提交问题求助

我帮你梳理了代码里的几个核心问题,这应该就是formset提交后没反应的原因,咱们一步步来修正:

核心问题分析
  1. 错误使用CreateView:CreateView是为单个模型对象创建设计的,而你需要处理的是关联多个食材的formset,用它会自带单个表单的逻辑干扰提交流程。
  2. success_url未正确解析:你写的success_url = "recipes:listrecipes"是纯字符串,Django无法识别为URL名称,必须用reverse_lazy解析。
  3. form_valid逻辑混乱:
    • 引用了未定义的parent_recipe_id变量,导致赋值失败
    • 调用了super().form_valid(form),触发了CreateView默认的单个表单保存逻辑,和formset的处理冲突
    • formset保存时没有正确关联父食谱对象
  4. 模板变量传递缺失:模板里用的referring_recipe_name和referring_recipe_id没有在视图中传递,虽然不影响提交,但会导致页面显示异常
修改后的代码

视图代码

from django.views.generic.edit import FormView
from django.urls import reverse_lazy
from django.shortcuts import redirect

class AddIngredientView(FormView):
    template_name = 'addingredientmultiple2.html'
    success_url = reverse_lazy('recipes:listrecipes')

    def get_context_data(self, **kwargs):
        data = super().get_context_data(**kwargs)
        # 获取当前要添加食材的父食谱
        parent_recipe = RecipeBase.objects.get(id=self.kwargs['pk'])
        # 用parent_recipe初始化formset,关联外键
        if self.request.POST:
            data['ingredients'] = AddIngredientFormset(self.request.POST, instance=parent_recipe)
        else:
            data['ingredients'] = AddIngredientFormset(instance=parent_recipe)
        # 传递模板需要的显示变量
        data['referring_recipe_name'] = parent_recipe.name
        data['referring_recipe_id'] = parent_recipe.id
        return data

    def form_valid(self, form):
        context = self.get_context_data()
        formset = context['ingredients']
        if formset.is_valid():
            # 先获取未保存的食材对象,批量设置关联关系
            ingredients = formset.save(commit=False)
            user = self.request.user
            for ingredient in ingredients:
                # 取消下面注释可设置用户字段
                # ingredient.creation_user = str(user)
                # ingredient.lastupdated_user = str(user)
                ingredient.parent_recipe = RecipeBase.objects.get(id=self.kwargs['pk'])
                ingredient.save()
            # 处理formset的删除操作(如果有)
            formset.save_m2m()
        # 直接重定向到成功页面,避免原CreateView的默认逻辑干扰
        return redirect(self.success_url)

表单及Formset代码(仅调整注释)

class AddIngredientForm(forms.ModelForm):
    quantity = forms.DecimalField(widget=forms.NumberInput(attrs={'data-placeholder': 0.00,'size': '8','label_tag': ''}))
    referenced_unit = forms.ModelChoiceField(queryset=UnitDetail.objects.all())
    referenced_ingredient = forms.ModelChoiceField(queryset=Ingredient.objects.all())

    class Meta:
        model = RecipeIngredient
        fields = ('quantity','referenced_unit','referenced_ingredient',)

# inlineformset_factory已经关联了RecipeBase和RecipeIngredient,instance参数会自动处理外键关联
AddIngredientFormset = inlineformset_factory(RecipeBase, RecipeIngredient, form=AddIngredientForm, extra=1, can_delete=True)

模板代码(优化表单属性)

{{ ingredients.media.css }}
<div class="container">
<h2>Add ingredients to {{ referring_recipe_name }}</h2>
<h4>{{ referring_recipe_id }}</h4>
</div>
<div class="col-md-4">
<form class="form-horizontal" method="post">{% csrf_token %}
<table class="table">
{{ ingredients.management_form }}
{% for form in ingredients.forms %}
{% if forloop.first %}
<thead>
<tr>
{% for field in form.visible_fields %}
<th>{{ field.label|capfirst }}</th>
{% endfor %}
</tr>
</thead>
{% endif %}
<tr class="formset_row">
{% for field in form.visible_fields %}
<td>
{# 包含表单隐藏字段 #}
{% if forloop.first %}
{% for hidden in form.hidden_fields %}
{{ hidden }}
{% endfor %}
{% endif %}
{{ field.errors.as_ul }}
{{ field }}
</td>
{% endfor %}
</tr>
{% endfor %}
</table>
<input class='btn btn-success' type="submit" value="Save"/>
<a href="{% url 'recipes:listrecipes' %}">back to the list</a>
</form>
</div>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script src="{% static 'formset/jquery.formset.js' %}"></script>
<script type="text/javascript">
$('.formset_row').formset({
    addText: 'ADD INGREDIENT',
    deleteText: 'REMOVE',
    prefix: 'ingredients'
});
</script>
{{ ingredients.media.js }}
修改说明
  • 换成FormView后,完全专注于formset的处理,避免了CreateView的单个表单逻辑干扰
  • 用instance=parent_recipe初始化formset,让inlineformset自动关联父食谱外键,保存时更顺畅
  • 修复了变量未定义的问题,确保食材对象能正确关联到父食谱
  • 移除了不必要的enctype="multipart/form-data"(没有文件上传需求)

内容的提问来源于stack exchange,提问作者qaccount345

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:35:06