models.BooleanField
チェックボックスの代わりに2つのラジオボタンとしてレンダリングするDjango 1.0.2のウィジェットはありますか?
11 に答える
Django 1.2 では、モデルフォームの「ウィジェット」メタ オプションが追加されました。
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
}
ブール値も 1/0 値として格納する SQLite db でこれをテストしましたが、カスタムの強制関数がなくても問題なく動作するようです。
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
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
これが私が見つけることができる最も簡単なアプローチです(私はDjango 1.5を使用しています):
class MyModelForm(forms.ModelForm):
yes_no = forms.BooleanField(widget=RadioSelect(choices=[(True, 'Yes'),
(False, 'No')]))
これは、「False」-> Trueの問題を回避する、ラムダを使用した迅速で汚い強制関数です。
...
boolfield = forms.TypedChoiceField(coerce=lambda x: x and (x.lower() != 'false'),
...
@Daniel Rosemanの回答に問題があるため、bool('False') --> Trueなので、ここで2つの回答を組み合わせて1つの解決策を作成しました。
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
これで動作します:)
また、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
別の解決策:
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)