Django动态表单实现问询:基于会议参与者生成观察者评分表单
Django动态会议评分表单实现指导
应用背景
多团队会议评分跟踪系统,每个团队含4-8名成员,培训周期内开展6次会议。每次会议推选1-2名成员作为参与者,要求所有成员至少参与一次会议,剩余成员为观察者,需记录观察者对会议的评分。
当前挑战
观察者数量随参与者选择动态变化(0-6人),需为每个观察者生成带评分输入的动态表单字段,并将评分数据保存至Observer模型。
现有进度
ScoreCreate视图已配置首位参与者,"其他参与者"下拉框可展示团队其他成员- 模板通过HTMX将选中的参与者信息传递给
observers视图,已能筛选出对应观察者,但无法生成可提交评分的动态表单字段
实现步骤
1. 定义观察者评分字段命名规则
为后端识别每个观察者的评分,需给评分字段设置结构化名称:observer_rating_{{ observer.id }},便于提交后遍历处理。
2. 修改观察者模板(all_observers.html)
替换原模板内容,生成绑定观察者ID的单选评分组:
{% for observer in observers %} <div class="d-flex align-items-center g-py-10 g-brd-bottom g-brd-gray-light-v3"> <div class="g-mr-20">{{ observer.name }}</div> <div class="ml-auto"> {% for choice in RATING_CHOICES %} <div class="form-check form-check-inline"> <input class="form-check-input" type="radio" name="observer_rating_{{ observer.id }}" id="rating_{{ observer.id }}_{{ choice.0 }}" value="{{ choice.0 }}" required> <label class="form-check-label" for="rating_{{ observer.id }}_{{ choice.0 }}">{{ choice.1 }}</label> </div> {% endfor %} </div> </div> {% empty %} <div class="text-center g-py-20">当前无观察者</div> {% endfor %}
3. 调整observers视图逻辑
补充传递评分选项到模板,修正观察者查询逻辑:
from .choices import RATING_CHOICES from django.db.models import Q def observers(request): participant_id = request.GET.get('participant') other_participant_id = request.GET.get('other_participant') team_id = request.GET.get('team') # 构建排除已选参与者的条件 exclude_ids = [participant_id] if other_participant_id and other_participant_id != '': exclude_ids.append(other_participant_id) # 查询团队内除已选参与者外的所有成员 observers = Participant.objects.filter(team_id=team_id).exclude(id__in=exclude_ids) return render(request, 'trial/partials/all_observers.html', { 'observers': observers, 'RATING_CHOICES': RATING_CHOICES })
4. 重写ScoreCreate表单保存逻辑
使用事务确保Score与Observer数据原子性保存:
from django.db import transaction class ScoreCreate(LoginRequiredMixin, CreateView): model = Score form_class = ScoreCreateForm template_name = 'score_create.html' success_url = '替换为你的成功跳转URL' def get_initial(self): # 修正初始值逻辑:通过团队slug获取对应成员 team = Team.objects.get(slug=self.kwargs['slug']) participant_id = self.kwargs['pk'] return { 'primary_participant': participant_id, } def form_valid(self, form): with transaction.atomic(): score = form.save() # 遍历请求中的观察者评分数据 for key, value in self.request.POST.items(): if key.startswith('observer_rating_'): observer_id = key.split('_')[-1] observer = Participant.objects.get(id=observer_id) Observer.objects.create( score=score, observer=observer, rating=value ) return super().form_valid(form)
5. 完善主模板HTMX触发逻辑
添加团队ID隐藏字段,确保观察者列表实时更新:
<form method="POST" name="score_participants"> {% csrf_token %} <!-- 隐藏字段传递团队ID --> <input type="hidden" name="team" value="{{ team.id }}"> <!-- 原表单内容保留,修正字段名与模型对应 --> <div class="d-flex g-mt-0 g-brd-top g-brd-gray-light-v3 g-bg-secondary"> <div class="g-mt-12 g-ml-10">参与者:</div> <div>{{ form.primary_participant|as_crispy_field }}</div> </div> <div class="d-flex g-mt-0 g-brd-top g-brd-gray-light-v3 g-bg-secondary"> <div class="g-mt-18 g-ml-10 g-mr-50">其他会议参与者姓名:</div> <div class="ml-auto g-mt-13 g-mr-10" hx-get="{% url 'observers' %}" hx-include="[name='score_participants']" hx-trigger="change from:[name='primary_participant'], change from:[name='secondary_participant']" hx-target="#observers"> {{ form.secondary_participant|as_crispy_field }} </div> </div> <div class="g-mt-0 g-brd-top g-brd-gray-light-v3"> <div id="observers"></div> </div> <!-- 提交按钮等内容 --> </form>
关键说明
- 事务机制避免
Score保存成功但Observer保存失败的情况 - 结构化字段命名是动态表单数据识别的核心
- HTMX同时监听主/次参与者的变化,确保观察者列表实时同步
内容的提问来源于stack exchange,提问作者William
相关产品推荐
相关产品推荐

