Django inlineformset无法提交问题求助
我帮你梳理了代码里的几个核心问题,这应该就是formset提交后没反应的原因,咱们一步步来修正:
核心问题分析
- 错误使用CreateView:CreateView是为单个模型对象创建设计的,而你需要处理的是关联多个食材的formset,用它会自带单个表单的逻辑干扰提交流程。
- success_url未正确解析:你写的
success_url = "recipes:listrecipes"是纯字符串,Django无法识别为URL名称,必须用reverse_lazy解析。 - form_valid逻辑混乱:
- 引用了未定义的
parent_recipe_id变量,导致赋值失败 - 调用了
super().form_valid(form),触发了CreateView默认的单个表单保存逻辑,和formset的处理冲突 - formset保存时没有正确关联父食谱对象
- 引用了未定义的
- 模板变量传递缺失:模板里用的
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
相关产品推荐
相关产品推荐

