Django Formset验证通过但返回空字典列表问题求助
问题解决:Django Formset cleaned_data 返回空字典列表
核心问题排查
- 表单字段定义错误:
InvitePlayerForm里直接把CheckboxInput(这是渲染控件类)当成字段类型用,正确的字段类型应该是BooleanField,再指定该控件。 - 模板控件命名不匹配:手动写的checkbox的
name格式是invited_<索引>,但Django Formset要求的格式是form-<索引>-invited,导致提交的数据无法被Formset识别。 - 自定义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
相关产品推荐
相关产品推荐

