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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 07:45:37