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

Django循环渲染考勤单选框无法为每个用户单独选值的解决方法

问题根源

全局仅能选中一个单选按钮的核心原因有两点:

  1. 循环渲染时所有考勤单选框共用同一个attendance表单字段,生成的所有单选框name属性完全一致,浏览器默认同name的radio控件属于同一选择组,全局仅能选中一个值
  2. 现有表单、视图逻辑没有关联考勤记录和对应用户,提交后只会生成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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 20:45:32