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

Django表单过滤外键选项报错Cannot unpack non-iterable object求助

问题原因

Django的ChoiceField要求传入的choices参数必须是由(实际存储值, 页面显示文本)格式的二元组组成的列表,你的代码里直接把Categoria模型实例列表传给了choices,Django在尝试拆包每一个选项为「值+显示文本」的二元组时,拿到的是单个Categoria对象,因此抛出不可迭代的错误。
此外对于外键关联的字段,直接使用ModelChoiceField比普通ChoiceField更适配,不需要手动处理选项格式。

解决方案

方案1:使用ModelChoiceField(更推荐)

直接修改表单的__init__方法,给categoria字段的queryset赋值过滤后的分类即可,不需要重新创建字段,会自动适配外键逻辑:

class ContatoForm(forms.ModelForm):
    class Meta:
        model = Contato
        exclude = ('created_by',)

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(ContatoForm, self).__init__(*args, **kwargs)
        # 直接修改原有字段的查询集,过滤当前用户创建的分类
        self.fields['categoria'].queryset = Categoria.objects.filter(created_by=self.user)

该方案会自动调用Categoria的__str__方法返回的内容作为选项显示文本,主键作为实际存储值,还自带外键字段的合法性校验,无需额外处理。

方案2:手动转换为ChoiceField要求的二元组格式

如果你一定要用ChoiceField,需要手动把查询到的分类实例转换成二元组列表:

class ContatoForm(forms.ModelForm):
    class Meta:
        model = Contato
        exclude = ('created_by',)

    def __init__(self, *args, **kwargs):
        self.user = kwargs.pop('user', None)
        super(ContatoForm, self).__init__(*args, **kwargs)
        # 手动构造符合要求的二元组列表,第一个元素是分类主键,第二个是页面显示名称
        category_choices = [(cat.id, cat.nome) for cat in Categoria.objects.filter(created_by=self.user)]
        self.fields['categoria'] = forms.ChoiceField(choices=category_choices)

补充:你视图里的form_categoria = CategoriaForm缺少实例化的括号,后续使用时如果报错可以检查这里,改为form_categoria = CategoriaForm()即可,该问题不影响本次报错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.23 16:15:04