Existe-t-il un widget dans Django 1.0.2 pour rendre un models.BooleanField
comme deux boutons radio au lieu d'une case à cocher?
Pour cela, vous pouvez remplacer la définition de champ dans 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
Django 1.2 a ajouté l'option Meta "widgets" pour les modelforms:
Dans votre models.py, spécifiez les "choix" pour votre champ booléen:
BOOL_CHOICES = ((True, 'Yes'), (False, 'No'))
class MyModel(models.Model):
yes_or_no = models.BooleanField(choices=BOOL_CHOICES)
Ensuite, dans votre forms.py, spécifiez le widget RadioSelect pour ce champ:
class MyModelForm(forms.ModelForm):
class Meta:
model = MyModel
widgets = {
'yes_or_no': forms.RadioSelect
}
J'ai testé cela avec une base de données SQLite, qui stocke également les booléens en tant que valeurs 1/0, et cela semble fonctionner correctement sans fonction de contrainte personnalisée.
En modifiant un peu la réponse de Daniel Roseman, vous pouvez résoudre le problème booléen ("False") = True de manière succincte en utilisant simplement des ints à la place:
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
Voici l'approche la plus simple que j'ai pu trouver (j'utilise Django 1.5):
class MyModelForm(forms.ModelForm):
yes_no = forms.BooleanField(widget=RadioSelect(choices=[(True, 'Yes'),
(False, 'No')]))
Dans Django 1.6, ce qui suit a fonctionné pour moi:
class EmailSettingsForm(ModelForm):
class Meta:
model = EmailSetting
fields = ['setting']
widgets = {'setting': RadioSelect(choices=[
(True, 'Keep updated with emails.'),
(False, 'No, don\'t email me.')
])}
Identique à la réponse de @ eternicode, mais sans modifier le modèle:
class MyModelForm(forms.ModelForm):
yes_no = forms.RadioSelect(choices=[(True, 'Yes'), (False, 'No')])
class Meta:
model = MyModel
widgets = {'boolfield': yes_no}
Je pense que cela ne fonctionne que dans Django 1.2+
Voici une fonction de coercition rapide et sale utilisant lambda, qui contourne le "faux" -> vrai problème:
...
boolfield = forms.TypedChoiceField(coerce=lambda x: x and (x.lower() != 'false'),
...
Souvenez-vous également que MySQL utilise tinyint pour Boolean, donc True/False sont en fait 1/0. J'ai utilisé cette fonction de contrainte:
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
Une autre solution:
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)
Comme il y a un problème dans la réponse de @Daniel Roseman, bool ('False') -> Vrai, alors maintenant j'ai combiné deux réponses ici pour faire une solution.
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
Maintenant, cela fonctionnera :)