Django循环渲染考勤单选框无法为每个用户单独选值的解决方法
问题根源
全局仅能选中一个单选按钮的核心原因有两点:
- 循环渲染时所有考勤单选框共用同一个
attendance表单字段,生成的所有单选框name属性完全一致,浏览器默认同name的radio控件属于同一选择组,全局仅能选中一个值 - 现有表单、视图逻辑没有关联考勤记录和对应用户,提交后只会生成1条考勤数据,无法匹配每个用户的考勤状态
解决方案
使用Django内置的modelformset_factory生成和用户数量匹配的表单集,每个表单单独对应用户的考勤记录,自动生成独立的radio选择组,提交后批量保存数据即可。
1. 调整forms.py
原有ModelForm保留即可,不需要额外修改结构:
from django import forms from .models import Attendance attendance_choices = ( ('absent', 'Afwezig'), ('allowedabsent', 'Geoorloofd afwezig'), ('present', 'Aanwezig'), ) class CreateAttendance(forms.ModelForm): class Meta: model = Attendance fields = ['attendance'] widgets = { 'attendance': forms.RadioSelect(choices=attendance_choices) }
2. 调整views.py
导入formset工厂方法,初始化时绑定表单和对应用户,提交时批量校验保存,补上原有逻辑缺失的外键赋值(原代码未给user、baksgewijs字段赋值,保存时会触发数据库约束错误):
from django.forms import modelformset_factory from django.shortcuts import render, HttpResponseRedirect, reverse from django.contrib import messages from .models import Attendance, Baksgewijs, Peloton from .forms import CreateAttendance from puma_core.models import User def baksgewijs_attendance(request): # 替换为你实际获取当前考勤批次的逻辑,比如从URL参数取对应Baksgewijs记录ID current_baksgewijs = Baksgewijs.objects.first() users = User.objects.all() # 生成和用户数量一致的表单集,不额外渲染空表单 AttendanceFormSet = modelformset_factory(Attendance, form=CreateAttendance, extra=0) if request.method == "POST": formset = AttendanceFormSet(request.POST, request.FILES) if formset.is_valid(): instances = formset.save(commit=False) # 给每条考勤记录绑定对应用户和考勤批次 for instance, user in zip(instances, users): instance.user = user instance.baksgewijs = current_baksgewijs instance.save() messages.success(request, "De aanwezigheid is opgeslagen") return HttpResponseRedirect(reverse("baksgewijs_index")) else: # GET请求初始化表单集,可设置默认考勤状态为present initial_data = [{'attendance': 'present'} for _ in users] formset = AttendanceFormSet(queryset=Attendance.objects.none(), initial=initial_data) # 将用户和对应表单一一打包传给模板 user_form_list = zip(users, formset) return render(request, 'baksgewijs/baksgewijs_attendance.html', { "user_form_list": user_form_list, "formset": formset })
3. 调整模板文件baksgewijs_attendance.html
必须渲染formset的管理表单(缺失会导致formset校验失败),遍历用户和表单的打包列表,独立渲染每个用户的单选组:
<form class="createattendance-form" action="" method="POST" enctype="multipart/form-data"> {% csrf_token %} <!-- formset依赖的管理字段,必须添加 --> {{ formset.management_form }} {{ formset.non_form_errors }} {% for user, form in user_form_list %} <div class="form-group"> <p><strong>{{ user.get_full_name|default:user.username }}</strong></p> <div> {{ form.attendance }} {{ form.attendance.errors }} </div> </div> {% endfor %} <br> <div class="form-group"> <button type="submit" class="btn btn-primary save">Save absence</button> </div> </form>
效果说明
修改后formset会自动给每个用户的单选框添加独立name前缀(例如form-0-attendance、form-1-attendance),天然按用户划分选择组,每个用户都能独立选择考勤状态,提交后会批量生成所有用户对应的考勤记录,不会再出现全局只能选一个单选框的问题。
内容的提问来源于stack exchange,提问作者Annelotte
相关产品推荐
相关产品推荐

