【问题标题】:Empty Label ChoiceField Django空标签ChoiceField Django
【发布时间】:2013-01-10 13:18:05
【问题描述】:

如何让ChoiceField 的标签表现得像ModelChoiceField?有没有办法设置empty_label,或者至少显示一个空白字段?

Forms.py:

    thing = forms.ModelChoiceField(queryset=Thing.objects.all(), empty_label='Label')
    color = forms.ChoiceField(choices=COLORS)
    year = forms.ChoiceField(choices=YEAR_CHOICES)

我已经尝试过这里建议的解决方案:

Stack Overflow Q - 设置 CHOICES = [('','All')] + CHOICES 导致内部服务器错误。

Stack Overflow Q2 - 在我的选择中定义 ('', '---------'), 后,仍然默认为列表中的第一项,而不是 ('', '---------'), 选择。

Gist - 尝试使用此处定义的 EmptyChoiceField,但无法使用 Django 1.4。

但是这些都不适合我。你会如何解决这个问题?感谢您的想法!

【问题讨论】:

  • 你找到解决办法了吗?
  • 嗨@Amyth,看看我发布的答案。

标签: django forms label


【解决方案1】:

请参阅ChoiceField 上的 Django 1.11 文档。 ChoiceField 的“空值”定义为空字符串'',因此您的元组列表应包含一个键'',映射到您要为空值显示的任何值。

### forms.py
from django.forms import Form, ChoiceField

CHOICE_LIST = [
    ('', '----'), # replace the value '----' with whatever you want, it won't matter
    (1, 'Rock'),
    (2, 'Hard Place')
]

class SomeForm (Form):

    some_choice = ChoiceField(choices=CHOICE_LIST, required=False)

注意,如果您希望表单字段是可选的,则可以通过使用required=False来避免表单错误

另外,如果您已经有一个没有空值的 CHOICE_LIST,您可以插入一个,以便它首先显示在表单下拉菜单中:

CHOICE_LIST.insert(0, ('', '----'))

【讨论】:

  • 我可以使用 (None, '----') 代替 ('', '----') 吗?我问的原因是在我没有那个空白条目之前,如果用户没有做出选择,我收到无。有了这个改变,我收到了 '' 并且现在有很多我失败的 if 语句
  • @Johan: 是的,如果选择来自元组值(none,'----'),则不会在form.cleaned_data 中传输。
  • 有人能谈谈空字符串值对计算平均值和其他数字的影响吗?
【解决方案2】:

这是我使用的解决方案:

from myapp.models import COLORS

COLORS_EMPTY = [('','---------')] + COLORS

class ColorBrowseForm(forms.Form):
    color = forms.ChoiceField(choices=COLORS_EMPTY, required=False, widget=forms.Select(attrs={'onchange': 'this.form.submit();'}))

【讨论】:

  • 如果 COLORS 是一个元组,你不能给它添加一个列表。如果您将 COLORS 声明为元组的元组,那么最好的方法就是 reczy 所说的。空白选择 = (('', '------'),) 空白选择 + 颜色
【解决方案3】:

你可以试试这个(假设你的选择是元组):

blank_choice = (('', '---------'),)
...
color = forms.ChoiceField(choices=blank_choice + COLORS)
year = forms.ChoiceField(choices=blank_choice + YEAR_CHOICES)

另外,我无法从你的代码中判断这是一个表单还是一个ModelForm,但它是后者,不需要在这里重新定义表单字段(你可以直接包含choices=COLORS和choices=YEAR_CHOICES模型字段。

希望这会有所帮助。

【讨论】:

  • 尝试将其与 ModelForm 一起使用会导致:TypeError: can only concatenate tuple (not "list") to tuple
  • @NickB 那么你的选择不是一个元组,所以你需要 blank_choice = [('', '----')]
【解决方案4】:

我知道你已经接受了一个答案,但我只是想发布这个以防有人遇到我遇到的问题,即接受的解决方案不适用于 ValueListQuerySet。您链接到的EmptyChoiceField 非常适合我(尽管我使用的是 django 1.7)。

class EmptyChoiceField(forms.ChoiceField):
    def __init__(self, choices=(), empty_label=None, required=True, widget=None, label=None, initial=None, help_text=None, *args, **kwargs):

        # prepend an empty label if it exists (and field is not required!)
        if not required and empty_label is not None:
            choices = tuple([(u'', empty_label)] + list(choices))

        super(EmptyChoiceField, self).__init__(choices=choices, required=required, widget=widget, label=label, initial=initial, help_text=help_text, *args, **kwargs) 

class FilterForm(forms.ModelForm):
    #place your other fields here 
    state = EmptyChoiceField(choices=People.objects.all().values_list("state", "state").distinct(), required=False, empty_label="Show All")

【讨论】:

  • 这是一个很好的解决方案。 Django 3.0 更新: EmptyChoice 字段类的最后一行应该以 super().__init__(choices=... 开头,您可以完全取出 *args
【解决方案5】:

聚会有点晚了..

完全不修改选项并仅使用小部件处理它怎么样?

from django.db.models import BLANK_CHOICE_DASH

class EmptySelect(Select):
    empty_value = BLANK_CHOICE_DASH[0]
    empty_label = BLANK_CHOICE_DASH[1]

    @property
    def choices(self):
        yield (self.empty_value, self.empty_label,)
        for choice in self._choices:
            yield choice

    @choices.setter
    def choices(self, val):
        self._choices = val

那就直接调用吧:

class SomeForm(forms.Form):
    # thing = forms.ModelChoiceField(queryset=Thing.objects.all(), empty_label='Label')
    color = forms.ChoiceField(choices=COLORS, widget=EmptySelect)
    year = forms.ChoiceField(choices=YEAR_CHOICES, widget=EmptySelect)

当然,EmptySelect 会被放置在某种 common/widgets.py 代码中,然后在您需要时,只需引用它即可。

【讨论】:

    【解决方案6】:

    由于模型中的整数字段,必须使用 0 而不是 u''。 (错误是 int() 以 10 为底的无效文字:')

    # prepend an empty label if it exists (and field is not required!)
    if not required and empty_label is not None:
        choices = tuple([(0, empty_label)] + list(choices))
    

    【讨论】:

      【解决方案7】:

      这不是同一种形式,但我是在 EmptyChoiceField 方法的启发下按照以下方式进行的:

      from django import forms
      from ..models import Operator
      
      
      def parent_operators():
          choices = Operator.objects.get_parent_operators().values_list('pk', 'name')
          choices = tuple([(u'', 'Is main Operator')] + list(choices))
          return choices
      
      
      class OperatorForm(forms.ModelForm):
          class Meta:
              model = Operator
              # fields = '__all__'
              fields = ('name', 'abbr', 'parent', 'om_customer_id', 'om_customer_name', 'email', 'status')
      
          def __init__(self, *args, **kwargs):
              super(OperatorForm, self).__init__(*args, **kwargs)
              self.fields['name'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
              self.fields['abbr'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
              self.fields['parent'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
              self.fields['parent'].choices = parent_operators()
              self.fields['parent'].required = False
              self.fields['om_customer_id'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
              self.fields['om_customer_name'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
              self.fields['email'].widget.attrs.update({'class': 'form-control m-input form-control-sm', 'type': 'email'})enter code here
      

      【讨论】:

        【解决方案8】:

        实现此目的的另一种方法是将选择小部件与其余小部件分开定义,并更改保存内容的方法。

        forms.py

        class CardAddForm(forms.ModelForm):
            category = forms.ModelChoiceField(empty_label='Choose category',
                                              queryset=Categories.objects.all(),
                                              widget=forms.Select(attrs={'class':'select-css'}))
        
            class Meta:
                **other model field**
        

        views.py 中你应该使用 obj.create(**form.cleaned_data) 而不是 form.save()

        【讨论】:

          猜你喜欢
          • 2010-12-18
          • 2014-02-24
          • 2013-07-18
          • 2010-10-20
          • 2018-10-25
          • 1970-01-01
          • 1970-01-01
          • 2014-07-11
          相关资源
          最近更新 更多