如何在Django表单ChoiceField中获取选项的标签?

83

我有一个ChoiceField,现在当我需要它的标签(label)时,该怎么做呢?

class ContactForm(forms.Form):
     reason = forms.ChoiceField(choices=[("feature", "A feature"),
                                         ("order", "An order")],
                                widget=forms.RadioSelect)

form.cleaned_data["reason"]只给我featureorder或类似的内容。


2
我认为你可能需要重新考虑哪个答案是被接受的。 - Dan Abramov
@Dan:为什么?你更喜欢哪一个? - webjunkie
@webjunkie 最多赞的那个是更加 Django 中心化的一个,需要在每个模型基础上写入更少的代码。 - Jack M.
1
@JackM,如果你指的是@shacker的回答,那它实际上并没有回答问题。get_FOO_display适用于django.db.models.ChoiceField而不是django.forms.ChoiceField。我认为截至Django 1.5目前,Andrés提供的回答是最好的解决方案。 - supervacuo
被接受的答案在更多情况下也适用。例如,如果您查询“FOO”表,但想要一个dict而不是模型(使用FOO.objects.values()),则可以进行微小的调整。@shacker的答案仅适用于完整的模型。 - Eduard Luca
有趣的是,在这个例子中,Django将featureorder视为值,而将A featureAn order视为标签。来源 - Advena
10个回答

171

请参阅Model.get_FOO_display()文档。因此,应该像这样:

ContactForm.get_reason_display()
在模板中使用时,像这样:
{{ OBJNAME.get_FIELDNAME_display }}

37
但它不是一个模型,而是一个表单。 - webjunkie
1
是的。这只适用于Django模型。表单不会模拟这种行为(尽管现在我希望它们能这样做)... - Gabriel Hurley
这对于模型来说很棒。谢谢你的提示。我想表单还需要以不同的方式完成。 - garromark
6
我遇到了同样的问题,不过是在使用ModelForm时。因此,对我来说{{form.instance.get_FIELDNAME_display}}非常好用。 - Michael

98

这可能有帮助:

reason = form.cleaned_data['reason']
reason = dict(form.fields['reason'].choices)[reason]

2
Django 允许分组选择。如果你有这些,那么这个方法就不适用了。 - mlissner

29
这是最简单的方法:模型实例参考:Model.get_FOO_display() 您可以使用此函数,它将返回显示名称:ObjectName.get_FieldName_display()ObjectName替换为您的类名,将FieldName替换为需要获取显示名称的字段。

4
好的,我会尽力完成翻译工作,并保证不改变原文意思。需要翻译的内容是:“NB the number of times you mention "model" in your answer (3) and the number of times @webjunkie mentioned it in the question (0).”我的回答中提到“model”的次数是3次,而@Webjunkie在问题中没有提到过这个词。 - supervacuo
chosen_label = form.instance.get_FOO_display() 正常工作。 - Anton Danilchenko

9
如果表单实例已绑定,您可以使用。
chosen_label = form.instance.get_FOO_display()

这只适用于ModelForm,问题没有提到。 - Tuttle

4

我想到了一个方法。可能有更简单的方法。我使用 python manage.py shell 进行了测试:

>>> cf = ContactForm({'reason': 'feature'})
>>> cf.is_valid()
True
>>> cf.fields['reason'].choices
[('feature', 'A feature')]
>>> for val in cf.fields['reason'].choices:
...     if val[0] == cf.cleaned_data['reason']:
...             print val[1]
...             break
...
A feature

注意:这可能不是非常符合Python的风格,但它展示了你需要的数据在哪里可以找到。

1
这种东西现在是否已经成为核心的一部分了?这不在表单API中令人难以置信,但我很难通过谷歌找到更好的解决方案。 - M. Ryan

3

好的。我知道这篇文章已经非常老了,但是阅读它对我很有帮助。我认为我有一些东西可以添加。

问题的关键在于模型方法。

ObjectName.get_FieldName_display()

对于表单无效。

如果您有一个不基于模型的表单,并且该表单具有选择字段,那么如何获取给定选择的显示值。

下面是一些可能对您有所帮助的代码。

您可以使用此代码从已发布的表单中获取选择字段的显示值。

display_of_choice = dict(dateform.fields['fieldnane'].choices)[int(request.POST.get('fieldname'))]

“int”是基于选择项为整数的情况下使用的。如果选择索引是一个字符串,则只需删除int(...)即可。”

有没有想法如何在模板中显示给定选择的显示值?即似乎{{form.get_fieldchoice_display}}不起作用。 - nick_rinaldi
上面有我的答案,而且后续的帖子中还有许多有效的答案。所有这些都是你可以使用的选项。如果你想要一个具体的答案,那么请发布你的实际代码,我们很乐意给你提供具体的答案。 - Paul West

3
您可以这样设置您的表单:

#forms.py
CHOICES = [('feature', "A feature"), ("order", "An order")]
class ContactForm(forms.Form):
     reason = forms.ChoiceField(choices=CHOICES,
                                widget=forms.RadioSelect)

那么这将为您提供所需的内容:

那么这将为您提供所需的内容:

reason = dict(CHOICES)[form.cleaned_data["reason"]]

1
确认Ardi和Paul的回应是针对表单而不是模型最好的。将Ardi的方法泛化到任何参数:
    class AnyForm(forms.Form):
        def get_field_name_display(self, field_name):
            return dict(self.fields[field_name].choices[self.cleaned_data[field_name]]

或者将这个方法放在一个单独的类中,然后在你的表单中进行子类化。

class ChoiceFieldDisplayMixin:
    def get_field_name_display(self, field_name):
        return dict(self.fields[field_name].choices[self.cleaned_data[field_name]]


class AnyCustomForm(forms.Form, ChoiceFieldDisplayMixin):
    choice_field_form = forms.ChoiceField(choices=[...])

现在对于任何选择字段调用相同的方法:

form_instance = AnyCustomForm()
form_instance.is_valid()
form_instance.get_field_name_display('choice_field_form')

现在混合使用元类,你最终会得到get_FOO_display的东西,你可以像处理模型一样轻松地在模板中使用它...这不是每个人都想要的吗? - benzkji

1

我正在使用 @Andrés Torres Marroquín 的方法,现在我想分享我的实现。

GOOD_CATEGORY_CHOICES = (
    ('paper', 'this is paper'),
    ('glass', 'this is glass'),
    ...
)

class Good(models.Model):
    ...
    good_category = models.CharField(max_length=255, null=True, blank=False)
    ....

class GoodForm(ModelForm):
    class Meta:
        model = Good
        ...

    good_category = forms.ChoiceField(required=True, choices=GOOD_CATEGORY_CHOICES)
    ...


    def clean_good_category(self):
        value = self.cleaned_data.get('good_category')

        return dict(self.fields['good_category'].choices)[value]

而结果是这是纸,而不是。 希望这可以帮助。

0

我想 @webjunkie 也许是对的。

如果你从 POST 表单中读取,则应执行以下操作:

def contact_view(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            contact = form.save()
            contact.reason = form.cleaned_data['reason']
            contact.save()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接