Django BooleanField 作为单选按钮?

Posted

技术标签:

【中文标题】Django BooleanField 作为单选按钮?【英文标题】:Django BooleanField as radio buttons? 【发布时间】:2010-10-25 16:14:51 【问题描述】:

在 Django 1.0.2 中是否有一个小部件可以将 models.BooleanField 呈现为两个单选按钮而不是一个复选框?

【问题讨论】:

【参考方案1】:

Django 1.2 为模型表单添加了“widgets”元选项:

在您的 models.py 中,为您的布尔字段指定“选择”:

BOOL_CHOICES = ((True, 'Yes'), (False, 'No'))

class MyModel(models.Model):
    yes_or_no = models.BooleanField(choices=BOOL_CHOICES)

然后,在您的 forms.py 中,为该字段指定 Radioselect 小部件:

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = 
            'yes_or_no': forms.RadioSelect
        

我已经使用 SQLite 数据库对此进行了测试,该数据库还将布尔值存储为 1/0 值,并且在没有自定义强制函数的情况下似乎可以正常工作。

【讨论】:

迄今为止最干净和最“Django”的解决方案。谢谢! 这很棒。我会稍微修改一下,通过使用from django.utils.translation import ugettext_lazy as _ 并将BOOL_CHOICES 更新为:BOOL_CHOICES = ((True, _('Yes')), (False, _('No'))) 来允许本地化版本的“是”和“否” 我认为用于本地化的额外代码会分散注意力。给读者的练习;) 在表单中定义选项更简单:***.com/a/8833454【参考方案2】:

您可以通过覆盖 ModelForm 中的字段定义来做到这一点:

class MyModelForm(forms.ModelForm):
    boolfield = forms.TypedChoiceField(
                   coerce=lambda x: x == 'True',
                   choices=((False, 'False'), (True, 'True')),
                   widget=forms.RadioSelect
                )

    class Meta:
         model = MyModel

【讨论】:

不幸的是这不起作用,因为 coerce=bool 被传递一个字符串值,而不是布尔值和 bool("False") => True。所以我不得不编写一个自定义强制函数来获取字符串值并转换为布尔值,然后它就起作用了。谢谢指点。 真的应该更新,因为正如@dar 所指出的,这实际上不会工作,因为bool('False') => True 不应该选择(('False', False), ('True', True))吗?换句话说,他们不应该反过来吗? 刚刚遇到这个,并想注意这个答案的更新。每this ticket:TypedChoiceField(coerce=lambda x: x =='True', choices=((False, 'No'), (True, 'Yes')), widget=forms.RadioSelect) 这种方式字段在form.changed_data中显示不正确,因为在比较表单输入值和初始值时使用了强制。将 bool True 传递给强制会导致 False,而传递给强制的表单结果中的“True”会导致 True,因此被称为 changed_data。我用以下强制解决了它: coerce=lambda x: ((x != 'False' and x is not False) or False)【参考方案3】:

稍微修改 Daniel Roseman 的答案,您可以通过使用 ints 来简洁地解决 bool("False") = True 问题:

class MyModelForm(forms.ModelForm):
    boolfield = forms.TypedChoiceField(coerce=lambda x: bool(int(x)),
                   choices=((0, 'False'), (1, 'True')),
                   widget=forms.RadioSelect
                )

class Meta:
     model = MyModel

【讨论】:

这不适用于我的编辑表单。该字段的当前值不会从模型中拉出。我改用了 eternicode 的答案。【参考方案4】:

这是我能找到的最简单的方法(我使用的是 Django 1.5):

class MyModelForm(forms.ModelForm):
    yes_no = forms.BooleanField(widget=RadioSelect(choices=[(True, 'Yes'), 
                                                            (False, 'No')]))

【讨论】:

这应该是正确的答案。 验证此解决方案是否有效,但请参阅note in the docs。您需要在字段上设置 required=False。【参考方案5】:

在 Django 1.6 中,以下内容对我有用:

class EmailSettingsForm(ModelForm):

    class Meta:
        model = EmailSetting
        fields = ['setting']
        widgets = 'setting': RadioSelect(choices=[
            (True, 'Keep updated with emails.'),
            (False, 'No, don\'t email me.')             
        ])

【讨论】:

【参考方案6】:

与@eternicode 的回答相同,但不修改模型:

class MyModelForm(forms.ModelForm):
    yes_no = forms.RadioSelect(choices=[(True, 'Yes'), (False, 'No')])

    class Meta:
        model = MyModel
        widgets = 'boolfield': yes_no

我认为这只适用于 Django 1.2+

【讨论】:

boolfield 指的是什么? @DataGreed 将其替换为您的字段名称。【参考方案7】:

这是一个使用 lambda 的快速而肮脏的强制函数,它解决了 "False" -> True 问题:

...
boolfield = forms.TypedChoiceField(coerce=lambda x: x and (x.lower() != 'false'),
...

【讨论】:

【参考方案8】:

由于@Daniel Roseman 的答案存在问题,bool('False') --> 是的,所以现在我在这里将两个答案合并为一个解决方案。

def boolean_coerce(value):
    # value is received as a unicode string
   if str(value).lower() in ( '1', 'true' ):
       return True
   elif str(value).lower() in ( '0', 'false' ):
       return False
   return None

class MyModelForm(forms.ModelForm):
boolfield = forms.TypedChoiceField(coerce= boolean_coerce,
               choices=((False, 'False'), (True, 'True')),
               widget=forms.RadioSelect
            )

class Meta:
     model = MyModel

现在这将起作用:)

【讨论】:

【参考方案9】:

还要记住 mysql 使用 tinyint 作为布尔值,所以 True/False 实际上是 1/0。我使用了这个强制函数:

def boolean_coerce(value):
    # value is received as a unicode string
    if str(value).lower() in ( '1', 'true' ):
        return True
    elif str(value).lower() in ( '0', 'false' ):
        return False
    return None

【讨论】:

【参考方案10】:

另一种解决方案:

from django import forms
from django.utils.translation import ugettext_lazy as _

def RadioBoolean(*args, **kwargs):
    kwargs.update(
        'widget': forms.RadioSelect,
        'choices': [
            ('1', _('yes')),
            ('0', _('no')),
        ],
        'coerce': lambda x: bool(int(x)) if x.isdigit() else False,
    )
    return forms.TypedChoiceField(*args, **kwargs)

【讨论】:

【参考方案11】:

django 3.0 版更新:

BOOLEAN_CHOICES = (('1', 'True label'), ('0', 'False label'))
  # Filtering fields
    True_or_false_question = forms.ChoiceField(
        label="Some Label3",
  # uses items in BOOLEAN_CHOICES
        choices = BOOLEAN_CHOICES,
        widget = forms.RadioSelect
    )

它给出了一个要点按钮列表,我不知道如何让它不这样做

【讨论】:

list-style-type: none; 为 项设置样式以移除光盘。 developer.mozilla.org/en-US/docs/Web/CSS/list-style-type

以上是关于Django BooleanField 作为单选按钮?的主要内容,如果未能解决你的问题,请参考以下文章

使用单选按钮在 Django admin 中选择项目

Axure:切换单选按扭,控制界面显示不同内容

C#单选按钮测验[重复]

如何在 Django 上将 True 设置为 BooleanField 的默认值?

自定义包含 django.forms.CheckboxInput() 的 django.forms.BooleanField() 的样式

mysql 的 Django BooleanField 默认值