has - Django BooleanField como botones de radio?
post django (10)
Aquí hay una función de coerción rápida y sucia usando lambda, que evita el "Falso" -> Verdadero problema:
...
boolfield = forms.TypedChoiceField(coerce=lambda x: x and (x.lower() != ''false''),
...
¿Hay un widget en Django 1.0.2 para representar un models.BooleanField
como dos botones de opción en lugar de una casilla de verificación?
Como hay un problema en la respuesta de @Daniel Roseman, bool (''False'') -> True, entonces ahora he combinado dos respuestas aquí para hacer una solución.
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
Ahora esto funcionará :)
Django 1.2 ha agregado la opción Meta "widgets" para modelos:
En su models.py, especifique las "opciones" para su campo booleano:
BOOL_CHOICES = ((True, ''Yes''), (False, ''No''))
class MyModel(models.Model):
yes_or_no = models.BooleanField(choices=BOOL_CHOICES)
Luego, en su forms.py, especifique el widget RadioSelect para ese campo:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
widgets = {
''yes_or_no'': forms.RadioSelect
}
He probado esto con un SQLite db, que también almacena booleanos como valores 1/0, y parece funcionar bien sin una función de coerción personalizada.
En Django 1.6, lo siguiente funcionó para mí:
class EmailSettingsForm(ModelForm):
class Meta:
model = EmailSetting
fields = [''setting'']
widgets = {''setting'': RadioSelect(choices=[
(True, ''Keep updated with emails.''),
(False, ''No, don/'t email me.'')
])}
Este es el enfoque más simple que pude encontrar (estoy usando Django 1.5):
class MyModelForm(forms.ModelForm):
yes_no = forms.BooleanField(widget=RadioSelect(choices=[(True, ''Yes''),
(False, ''No'')]))
Lo mismo que la respuesta de @eternicode, pero sin modificar el modelo:
class MyModelForm(forms.ModelForm):
yes_no = forms.RadioSelect(choices=[(True, ''Yes''), (False, ''No'')])
class Meta:
model = MyModel
widgets = {''boolfield'': yes_no}
Creo que esto solo funciona en Django 1.2+
Modificando un poco la respuesta de Daniel Roseman, podrías arreglar el bool ("False") = verdadero problema sucintamente con solo usar ints:
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
Otra solución:
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)
Puede hacer esto anulando la definición de campo en 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
También recuerde que MySQL usa tinyint para Boolean, por lo que True / False son en realidad 1/0. Usé esta función de coerción:
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