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

为什么Django表单中动态生成的ChoiceField在模板中无法正常渲染?

问题原因

Django Form 的字段渲染、数据绑定、校验逻辑仅会处理内置的 self.fields 字典中存储的字段。你把动态生成的 ChoiceField 放在了自定义的 SundryFields 字典中,Django 不会对这些字段做任何处理,直接在模板输出时就会显示字段类的内存地址,也不会参与后续的表单校验和数据清洗。

修复步骤

1. 修改表单类代码

将动态生成的物料字段存入 self.fields,同时单独存储字段名列表方便后续遍历,避免和表单原有字段冲突:

name = forms.CharField(label="员工姓名", max_length = 200, required = False)
jobsite = forms.CharField(label="工作地点", max_length = 200, required = True)
date_needed = forms.DateField(initial = now, required = True)

def __init__(self, *args, **kwargs):
    sundries = kwargs.pop('sundries')
    super(CreateNewOrder, self).__init__(*args, **kwargs)
    # 存储动态生成的物料字段名,方便后续遍历
    self.sundry_field_names = []
    for sundry in sundries:
        # 生成0到可用库存的可选值
        quantity_list = [(i, i) for i in range(sundry.quantity_available + 1)]
        # 加前缀避免和其他字段重名
        field_name = f"sundry_{sundry.name}"
        self.fields[field_name] = forms.ChoiceField(label=sundry.name, choices=quantity_list)
        self.sundry_field_names.append(field_name)

# 新增方法:返回所有物料字段的可渲染实例,方便模板调用
def get_sundry_fields(self):
    return [self[field_name] for field_name in self.sundry_field_names]

2. 修改模板代码

直接调用表单新增的 get_sundry_fields 方法遍历渲染物料下拉框:

{% block title %}物料申请{% endblock %}
{% block content %}
    <h1>当前可用物料列表</h1> 
    <form method = "post" action="/orders/"> 
        {% csrf_token %}
        <div class="mb-3"> 
            <ul>
            <li>姓名: {{form.name}}</li>
            <li>工作地点: {{form.jobsite}}</li>
            <li>需用日期: {{form.date_needed}}</li>
            </ul>
        </div>
        <ul> 
        {% for field in form.get_sundry_fields %}
            <li>{{ field.label }}: {{ field }} </li> 
        {% endfor %}
        </ul>
        <button type="submit" name="submit">提交申请</button>
    </form>
{% endblock %}

3. 修改视图中的数据处理逻辑

适配加了前缀的字段名,提取物料名称和申请数量:

def orders(response):
    if response.method == "POST":
        form = CreateNewOrder(response.POST, sundries = Sundry.objects.all())
        if form.is_valid():
            cleaned_data = form.cleaned_data
            order = Order(name=cleaned_data["name"], jobsite=cleaned_data["jobsite"], date_needed=cleaned_data["date_needed"])
            order.save()
            del cleaned_data["name"]
            del cleaned_data["jobsite"]
            del cleaned_data["date_needed"]
            
            def find_requested(cleaned_data):
                requested = []
                for name, value in cleaned_data.items():
                    # 过滤物料字段,且申请数量大于0
                    if name.startswith("sundry_") and int(value) > 0:
                        sundry_name = name.replace("sundry_", "", 1)
                        requested.append((sundry_name, value))
                return requested
            
            for sundry_name, quantity in find_requested(cleaned_data):
                i = Item(order=order, text=sundry_name, quantity_requested=quantity)
                i.save()
                Sundry.objects.filter(name=i.text).update(quantity_available = F('quantity_available') - i.quantity_requested)
            
            subject = 'QCE仓库 - 申请单号#' + str(order.pk)
            message = '申请人: ' + order.name + "\n"
            for item in order.item_set.all():
                message += ("申请物料: " + item.text + " 数量: " + str(item.quantity_requested) + "\n")
            message += ("需用日期: " + str(order.date_needed))
            email_from = settings.EMAIL_HOST_USER
            recipient_list = ['braxtonagoss@gmail.com']
            send_mail(subject, message, email_from, recipient_list)
            return HttpResponseRedirect('thanks')
    else: 
        form = CreateNewOrder(sundries = Sundry.objects.all())
    return render(response, "main/order.html", {"form":form} )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 01:12:00