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

如何在Django中用单个表单保存多个模型对象实例?

解决方案

1. 修正模板循环与表单结构

首先你的模板遍历AnswerItem的写法有误,因为AnswerMenu和AnswerItem是外键关联,需要通过反向关联获取对应选项。同时要把所有单选框包裹在一个<form>标签内:

<form method="post" action="{% url '你的提交视图URL名称' %}">
    {% csrf_token %}
    {% for answer_menu in answer_menus %}
        <div>{{ answer_menu.menu_name }}</div>
        {% for answer_item in answer_menu.answeritem_set.all %}
            <p>
                <label>
                    <input id="{{ answer_item.pk }}" name="{{ answer_menu.pk }}" type="radio" value="{{ answer_item.pk }}">
                    {{ answer_item.item_name }}
                </label>
            </p>
        {% endfor %}
    {% endfor %}
    <button type="submit">提交答案</button>
</form>

注意:

  • 给单选框添加value="{{ answer_item.pk }}",提交时才能传递选中选项的ID
  • 用answer_menu.answeritem_set.all()遍历该菜单下的所有选项(如果给AnswerMenu的answer_item字段设置了related_name,比如related_name='items',就改成answer_menu.items.all())

2. 视图中处理POST请求并批量创建实例

可以用基于函数的视图,或是给现有ListView添加POST处理逻辑:

基于函数的视图示例

from django.shortcuts import redirect, get_object_or_404
from .models import AnswerMenu, AnswerItem, QuestionAnswer

def submit_answers(request):
    if request.method == 'POST':
        # 遍历POST键值对,键是AnswerMenu的PK,值是选中的AnswerItem的PK
        for menu_pk, item_pk in request.POST.items():
            # 排除csrf令牌等非菜单PK的键
            if menu_pk == 'csrfmiddlewaretoken':
                continue
            try:
                menu = get_object_or_404(AnswerMenu, pk=menu_pk)
                item = get_object_or_404(AnswerItem, pk=item_pk)
                # 创建QuestionAnswer实例
                QuestionAnswer.objects.create(answer=menu, answer_item=item)
            except ValueError:
                # 处理非法PK值
                continue
        # 提交成功后重定向到结果页或原页面
        return redirect('结果页URL名称')
    # GET请求直接重定向到菜单展示页
    return redirect('菜单展示页URL名称')

基于类的ListView扩展POST处理

如果用的是ListView,重写post方法:

from django.views.generic import ListView
from django.urls import reverse
from .models import AnswerMenu, AnswerItem, QuestionAnswer

class AnswerMenuListView(ListView):
    model = AnswerMenu
    context_object_name = 'answer_menus'
    template_name = '你的模板路径.html'

    def post(self, request, *args, **kwargs):
        for menu_pk, item_pk in request.POST.items():
            if menu_pk == 'csrfmiddlewaretoken':
                continue
            try:
                menu = AnswerMenu.objects.get(pk=menu_pk)
                item = AnswerItem.objects.get(pk=item_pk)
                QuestionAnswer.objects.create(answer=menu, answer_item=item)
            except (AnswerMenu.DoesNotExist, AnswerItem.DoesNotExist, ValueError):
                continue
        return redirect(self.get_success_url())

    def get_success_url(self):
        # 定义提交成功后的跳转URL
        return reverse('结果页URL名称')

3. 性能优化建议

如果菜单数量较多,用bulk_create批量创建实例提升效率:

question_answers = []
for menu_pk, item_pk in request.POST.items():
    if menu_pk == 'csrfmiddlewaretoken':
        continue
    try:
        menu = AnswerMenu.objects.get(pk=menu_pk)
        item = AnswerItem.objects.get(pk=item_pk)
        question_answers.append(QuestionAnswer(answer=menu, answer_item=item))
    except (AnswerMenu.DoesNotExist, AnswerItem.DoesNotExist, ValueError):
        continue
QuestionAnswer.objects.bulk_create(question_answers)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.15 07:20:29