2009-05-12 10 views

Répondre

58

Vous pouvez le faire en remplaçant la définition du champ dans la 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 
+7

Malheureusement, cela ne fonctionne pas, parce que le coerce = bool reçoit une valeur de chaîne, et non la valeur booléenne et bool ("False") => True. J'ai donc dû écrire une fonction de coercition personnalisée pour prendre la valeur de chaîne et la convertir en bool, alors cela a fonctionné. Merci pour le pointeur. – dar

+1

Devrait vraiment être mis à jour car, comme le note @dar, cela ne fonctionnera PAS puisque 'bool ('False')' => 'True'. –

+0

@ Daniel, il ne fonctionne pas, bool ('Faux') renvoie True –

3

Rappelez-vous aussi que MySQL utilise tinyint pour booléenne, donc Vrai/Faux sont en fait 1/0. J'ai utilisé cette fonction coerce:

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 
30

Modifier la réponse de Daniel Roseman un peu, vous pouvez fixer le bool (« Faux ») = vrai problème de façon succincte en utilisant simplement 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 
+2

Cela ne fonctionne pas sur mon formulaire d'édition. La valeur actuelle du champ n'est pas extraite du modèle. J'ai utilisé la réponse d'eternicode à la place. – Dave

5

Voici un rapide & fonction coerce sale en utilisant lambda, qui obtient autour de la "Faux" -> vrai problème:

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

Django 1.2 a ajouté l'option Meta "widgets" pour 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é ceci avec un DB SQLite, qui stocke également des booléens comme valeurs 1/0, et il semble fonctionner correctement sans une fonction de coercition personnalisée.

+4

La solution la plus propre et la plus "Django" de loin. Merci! –

+0

C'est génial. Je voudrais le modifier légèrement pour permettre des versions localisées de 'Oui' et 'Non' en utilisant 'from 'de django.utils.translation importer ugettext_lazy en tant que _' et mettre à jour' BOOL_CHOICES' être: 'BOOL_CHOICES = ((True, _ ('Oui')), (Faux, _ ('Non'))) ' – tatlar

+5

Je pense que le code supplémentaire pour le localiser serait distraire du point. Un exercice pour le lecteur;) – eternicode

3

Comme il y a problème, en réponse Roseman @ Daniel, bool (« Faux ») -> Il est vrai que 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 ceci fonctionne :)

3

Comme 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+

3

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) 
6

Voici l'approche la plus simple que je pourrais trouver (j'utilise Django 1.5):

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

Cela devrait être la bonne réponse. –

+0

Vérification de cette solution fonctionne, mais voir la [note dans les docs] (https://docs.djangoproject.com/en/1.10/ref/forms/fields/#booleanfield). Vous devez définir required = False sur le terrain. – grokpot

9

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.')    
     ])} 
Questions connexes