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

Django Formset验证通过但返回空字典列表问题求助

问题解决:Django Formset cleaned_data 返回空字典列表

核心问题排查

  1. 表单字段定义错误:InvitePlayerForm里直接把CheckboxInput(这是渲染控件类)当成字段类型用,正确的字段类型应该是BooleanField,再指定该控件。
  2. 模板控件命名不匹配:手动写的checkbox的name格式是invited_<索引>,但Django Formset要求的格式是form-<索引>-invited,导致提交的数据无法被Formset识别。
  3. 自定义Formset逻辑冗余:设置empty_permitted=False完全没必要,反而可能干扰数据解析。

分步修正

1. 修复 forms.py

# forms.py
from django import forms

class InvitePlayerForm(forms.Form):
    """
    用于邀请玩家加入新游戏的表单
    """
    # 改用BooleanField字段,指定CheckboxInput为渲染控件
    invited = forms.BooleanField(required=False, widget=forms.CheckboxInput())

# 移除多余的自定义Formset,直接用默认实现即可

2. 简化 views.py

不需要从session读取玩家数量,直接用POST里的TOTAL_FORMS即可:

# views.py
from django.shortcuts import render, redirect
from django.urls import reverse
from .forms import InvitePlayerForm
from django.forms import formset_factory
from .models import CustomUser

def create_game_players(request):
    context = dict()
    if request.method == "POST":
        # 直接初始化Formset,无需指定extra
        invite_formset = formset_factory(InvitePlayerForm)
        invite_forms = invite_formset(data=request.POST)

        print(f"Formset valid: {invite_forms.is_valid()}")
        print(f"request.POST: {request.POST}")
        print(f"changed_data: {invite_forms.has_changed()}")  # 注意要调用方法,加()

        if invite_forms.is_valid():
            data = invite_forms.cleaned_data
            print(f"Cleaned data: {data}")
            # 处理选中的玩家示例
            selected_players = []
            player_list = list(CustomUser.objects.all())
            for idx, form_data in enumerate(data):
                if form_data.get('invited'):
                    selected_players.append(player_list[idx])
            # 后续业务逻辑...
        return redirect(reverse("game_list_view"))

    else:
        player_list = list(CustomUser.objects.all())
        # 生成对应数量的表单
        invite_formset = formset_factory(InvitePlayerForm, extra=len(player_list))
        # 把表单和玩家列表配对传入模板
        context["form_player_pairs"] = zip(invite_formset(), player_list)

    return render(request, "create_game_players.html", context)

3. 修正模板 create_game_players.html

用Form自带的字段渲染,自动生成符合要求的name属性:

<h4>邀请玩家</h4>
<div class="form-group">
    <form method="post">
        {% csrf_token %}
        <!-- 渲染Formset管理表单 -->
        {% for form, player in form_player_pairs %}
            {{ form.id }}
        {% endfor %}
        {{ form_player_pairs.0.0.formset.management_form.as_p }}

        <table class="table table-hover">
            <thead>
                <tr>
                    <th>姓名</th>
                    <th>邀请</th>
                </tr>
            </thead>
            <tbody>
                {% for invite_form, player in form_player_pairs %}
                <tr>
                    <td>{{ player.first_name }} {{ player.last_name }}</td>
                    <td>{{ invite_form.invited }}</td>
                </tr>
                {% endfor %}
            </tbody>
        </table>
        <button type="submit" class="btn btn-info btn-lg btn-block">下一步</button>
    </form>
</div>

验证效果

修正后提交表单,cleaned_data会返回包含invited状态的字典列表,示例:

Cleaned data: [{'invited': True}, {'invited': True}, {'invited': False}, ...]

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 13:20:39