Django BooleanField作为单选按钮?

dar*_*dar 56 django django-models django-forms

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

ete*_*ode 86

Django 1.2为模型添加了"小部件"Meta选项:

在models.py中,为布尔字段指定"choices":

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

class MyModel(models.Model):
    yes_or_no = models.BooleanField(choices=BOOL_CHOICES)
Run Code Online (Sandbox Code Playgroud)

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

class MyModelForm(forms.ModelForm):
    class Meta:
        model = MyModel
        widgets = {
            'yes_or_no': forms.RadioSelect
        }
Run Code Online (Sandbox Code Playgroud)

我用SQLite数据库测试了它,它也将布尔值存储为1/0值,并且它似乎在没有自定义强制函数的情况下工作正常.

  • 我认为本地化它的额外代码会分散注意力.为读者练习;) (5认同)
  • 到目前为止最干净,最"Django"的解决方案.谢谢! (4认同)

Dan*_*man 62

您可以通过覆盖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
Run Code Online (Sandbox Code Playgroud)

  • 不幸的是,这不起作用,因为coerce = bool传递的是字符串值,而不是boolean值和bool("False")=> True.所以我不得不编写一个自定义的强制函数来获取字符串值并转换为bool,然后它就可以了.谢谢你的指针. (7认同)
  • 刚刚遇到这个问题,并想注意此答案的更新有效。每 [这张票](https://code.djangoproject.com/ticket/2723#comment:18): `TypedChoiceField(coerce=lambda x: x =='True', choice=((False, 'No') , (True, 'Yes')), widget=forms.RadioSelect)` (2认同)
  • 这样该字段在 form.changed_data 中显示不正确,因为在比较表单输入值和初始值时使用了强制。将 bool True 传递给 coerce 导致 False 和“True”,从传递给 coerce 的表单结果结果为 True,因此被称为changed_data。我用以下强制解决了它: coerce=lambda x: ((x != 'False' and x is not False) or False) (2认同)

小智 30

修改丹尼尔罗斯曼的答案,你可以通过使用整数来简单地修复bool("False")=真正的问题:

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
Run Code Online (Sandbox Code Playgroud)

  • 这不适用于我的编辑表单.该字段的当前值不是从模型中提取的.我使用了eternicode的答案. (2认同)

Rac*_*ole 10

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

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

  • 验证此解决方案是否有效,但请参阅[文档中的注释](https://docs.djangoproject.com/en/1.10/ref/forms/fields/#booleanfield)。您需要在字段上设置 required=False。 (2认同)

小智 10

在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.')             
        ])}
Run Code Online (Sandbox Code Playgroud)


af_*_*f__ 5

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

...
boolfield = forms.TypedChoiceField(coerce=lambda x: x and (x.lower() != 'false'),
...
Run Code Online (Sandbox Code Playgroud)


Ahs*_*san 5

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

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
Run Code Online (Sandbox Code Playgroud)

现在这可以工作了:)


ypr*_*rez 5

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

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

    class Meta:
        model = MyModel
        widgets = {'boolfield': yes_no}
Run Code Online (Sandbox Code Playgroud)

我认为这只适用于Django 1.2+