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

Django中如何更新M2M字段关联对象的属性值

Django多对多关联候选人票数更新实现

直接按以下步骤修改即可,代码可直接复用。

模板层修正

原模板存在循环变量重名、输入框无标识、缺少CSRF令牌三个问题,替换为如下代码:

<h5>{{ object }}</h5>
<form method="POST">
    {% csrf_token %}
    {{ form.as_p }}
    <hr>
    <h6>关联候选人票数设置</h6>
    {% for candidate in object.candidates.all %}
    <div style="margin: 10px 0;">
        <label>{{ candidate.name }}:</label>
        <input type="number" min="0" name="candidate_votes_{{ candidate.id }}" value="{{ candidate.votes }}" required>
    </div>
    {% endfor %}
    <button type="submit">保存全部修改</button>
</form>

输入框统一用candidate_votes_候选人ID的命名规则,后端可以直接解析匹配,前端加min=0限制非法负数输入。

视图层逻辑补全

POST处理逻辑加了数据合法性校验和事务保证,避免脏数据:

from django.db import transaction
from django.http import HttpResponseBadRequest
from django.shortcuts import redirect, render

def constituency_detail(request, pk):
    obj = get_object_or_404(Constituencies, id=pk)
    form = ConstituenciesForm(request.POST or None, instance=obj)

    if request.method == 'POST' and form.is_valid():
        # 开启数据库事务,所有更新要么全成功要么全回滚
        with transaction.atomic():
            constituency = form.save()
            # 预取当前选区合法的候选人ID集合,防止越权修改
            valid_candidate_ids = set(constituency.candidates.values_list('id', flat=True))

            for param_key, param_val in request.POST.items():
                if param_key.startswith('candidate_votes_'):
                    candidate_id = param_key.split('_')[-1]
                    # 校验参数合法性
                    if not candidate_id.isdigit() or int(candidate_id) not in valid_candidate_ids:
                        return HttpResponseBadRequest("请求参数非法")
                    if not param_val.isdigit():
                        return HttpResponseBadRequest("票数必须是非负整数")
                    # 更新对应候选人票数
                    Candidates.objects.filter(id=int(candidate_id)).update(votes=int(param_val))
            
            # 保存成功后重定向,避免刷新重复提交
            return redirect('constituency_detail', pk=pk)

    return render(request, 'template.html', {'object': obj, 'form': form})

注意点

  • 不要直接信任前端传的候选人ID,必须校验该候选人确实属于当前选区,防止恶意构造请求篡改非关联候选人数据
  • 事务是必须的,避免出现选区信息更新成功、但部分候选人票数更新失败的数据不一致问题
  • 所有输入值必须做类型校验,避免非数字值写入数据库触发异常

内容的提问来源于stack exchange,提问作者afi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 19:27:29