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

Django内联表单集更新验证失败,返回空列表错误

问题描述

创建功能运行正常,但更新功能出现异常:每个内联表单集都会返回1个空列表[]形式的错误。相关代码及打印输出如下:

forms.py

StructureFormset = inlineformset_factory(Plan, Structure,
        fields = (
            'material_type',
            'weight',
            'thickness',
            'provider'
        ),
        extra=0,
        can_delete=True
        )

TestFormset = inlineformset_factory(Plan, Test,
        fields=(
            'essay',
            'critic',
            'spec'
        ),
        extra = 0,
        can_delete=True
        )

class PlanForm(ModelForm):
    class Meta:
        model = Plan
        fields = (
            'format',
            'pc',
            'revission',
            'rev_date',
            'client',
            'product',
            'gp_code',
            'code',
            'observation',
            'continuation',
            'dispatch_conditions',
            'elaborator',
            'reviewer'          
        )
        localized_fields=('rev_date',)

views.py

def editPlan(request, pk):

    plan = Plan.objects.get(id = pk)

    form = PlanForm(instance = plan)    
    sformset = StructureFormset(instance=plan)    
    tformset = TestFormset(instance=plan)

    context = {
            'form': form,
            'sformset': sformset,
            'tformset': tformset
        }

    if request.method == 'POST':
        print('----------------------------request----------------------------')
        print(request.POST)

        form = PlanForm(request.POST, instance = plan)

        sformset = StructureFormset(request.POST, instance=plan, prefix='structure')        
        tformset = TestFormset(request.POST, instance=plan, prefix='test')

        if form.is_valid() and sformset.is_valid() and tformset.is_valid():

            print('-----------------------is valid-----------------------')

            form.save()

            instances = sformset.save(commit=False)
            for instance in instances:
                sformset.save_m2m()
                instance.save()                      

            tformset.save()           

            return redirect('/plans/')    
        else:#printing errors
            print('-----------------------is not valid-----------------------')
            print(sformset.total_error_count())
            print(sformset.errors)
            print(tformset.total_error_count())
            print(tformset.errors)

    return render(request, 'home/plan_forms.html', context)

template.html

{{ tformset.management_form }}
<table>
    <thead>
        <tr>
            <th>Essay</th>
            <th>
                <abb title="Critical Variable">Crit.</abb>
            </th>
            <th>Spec</th>
            {% if tformset.instance.pk %}
            <th class="text-center px-1 col-1 pb-2">
                <i class="material-icons">delete</i>
            </th>
            {% endif %}
        </tr>
    </thead>
    <tbody id="tform_set">

        <!--Test form goes here-->

        {% if tformset %}
        {% for tt in tformset %}
        {% for hidden in tt.hidden_fields %}
        {{ hidden }}
        {% endfor %}
        <tr>
            <td>
                {{ tt.essay }}
            </td>
            <td class="px-1 col-1 text-center justify-content-center">
                {{ tt.critic }}
            </td>
            <td>
                {{ tt.spec }}
            </td>
            <td>
                {% if tt.instance.pk %}{{ tt.DELETE }}{% endif %}
            </td>
        </tr>
        {% endfor %}
        {% endif %}
    </tbody>

    <tbody id="tempty_form" style="display:none !important;">
        <tr>
            <td>
                {{ tformset.empty_form.essay }}
            </td>
            <td>
                {{ tformset.empty_form.critic }}
            </td>
            <td>
                {{ tformset.empty_form.spec }}
            </td>
        </tr>
    </tbody>
</table>

{{ sformset.management_form }}
<table>
    <thead>
        <tr>
            <th>Material</th>
            <th>Weight (g/m²)</th>
            <th>Thickness (μ)</th>
            <th>Provider</th>
            {% if sformset.instance.pk %}
            <th class="text-center col-1 px-1 pb-2">
                <i class="material-icons">delete</i>
            </th>
            {% endif %}
        </tr>
    </thead>
    <tbody id="sform_set">

        <!--Structure form goes here-->
        {% if sformset %}
        {% for ss in sformset %}
        {% for hidden in ss.hidden_fields %}
        {{ hidden }}
        {% endfor %}
        <tr>
            <td>
                {{ ss.material_type }}
            </td>
            <td>
                {{ ss.weight }}
            </td>
            <td>
                {{ ss.thickness }}
            </td>
            <td>
                {{ ss.provider }}
            </td>
            <td>
                {% if ss.instance.pk %}{{ ss.DELETE }}{% endif %}
            </td>
        </tr>
        {% endfor %}
        {% endif %}
    </tbody>

    <tbody id="sempty_form" style="display:none !important;">
        <tr>
            <td>
                {{ sformset.empty_form.material_type }}
            </td>
            <td>
                {{ sformset.empty_form.weight }}
            </td>
            <td>
                {{ sformset.empty_form.thickness }}
            </td>
            <td>
                {{ sformset.empty_form.provider }}
                </div>
            </td>
        </tr>
    </tbody>
</table>

打印输出

-----------------------is not valid-----------------------
1
[]
1
[]

解决方案

问题根源

GET请求初始化表单集时未指定prefix,但POST请求时添加了prefix='structure'和prefix='test',导致前后表单集的字段命名不匹配,无法正确识别POST数据,进而触发空验证错误。另外save_m2m()的调用位置错误。

修复步骤

  1. 统一表单集的prefix:在GET请求初始化表单集时,添加与POST一致的prefix参数:
# 修改views.py中GET部分的表单集初始化代码
sformset = StructureFormset(instance=plan, prefix='structure')    
tformset = TestFormset(instance=plan, prefix='test')
  1. 修正save_m2m()调用位置:save_m2m()是针对整个表单集的方法,不需要在循环内部调用,应放在实例保存循环之后:
# 修改sformset保存的代码块
instances = sformset.save(commit=False)
for instance in instances:
    instance.save()                      
sformset.save_m2m()

验证

修改后重新测试更新功能,表单集将能正确识别POST提交的数据,验证通过后正常保存更新。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 03:30:41