2009-05-12 11 views

Respuesta

58

usted puede hacer esto cancelando la definición de campo en el 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

Desafortunadamente esto no funcionó, porque el coerce = bool se está pasando un valor de cadena, y no el valor booleano y bool ("False") => True. Así que tuve que escribir una función de coerción personalizada para tomar el valor de la cadena y convertir a bool, luego funcionó. Gracias por el puntero. – dar

+1

Realmente debería actualizarse ya que, como notas @dar, esto en realidad NO funcionará desde 'bool ('False')' => 'True'. –

+0

@Daniel, no funciona, bool ('False') devuelve True –

3

Asimismo, recuerda que MySQL utiliza tinyint de Boole, por lo Verdadero/Falso son en realidad 1/0. He utilizado esta función coaccionar:

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

Modificación de la respuesta de Daniel Roseman un poco, se puede fijar el bool ("falso") = True problema de forma sucinta sólo por el uso enteros en su lugar:

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

Esto no está funcionando en mi formulario de edición. El valor actual del campo no se extrae del modelo. Usé la respuesta de eternicode en su lugar. – Dave

5

Aquí hay una rápida & función de coaccionar sucia usando lambda, que se pone alrededor de la "falsa" -> el verdadero problema:

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

Django 1.2 ha añadido la opción de "widgets" Meta para modelforms:

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.

+4

La solución más limpia y más "Django" y de lejos. ¡Gracias! –

+0

Esto es genial. Lo modificaría ligeramente para permitir versiones localizadas de 'Sí' y 'No' usando 'from django.utils.translation import ugettext_lazy as _' y actualizando' BOOL_CHOICES' para que sea: 'BOOL_CHOICES = ((True, _ ('Sí')), (False, _ ('No'))) ' – tatlar

+5

Creo que el código extra para localizarlo distraería del punto. Un ejercicio para el lector;) – eternicode

3

Como hay un problema en @Daniel Roseman answer, bool ('False') -> Es cierto, así que 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 bien, esto va a funcionar :)

3

Igual 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 sólo funciona en Django 1.2+

3

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

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')])) 
+0

Esta debería ser la respuesta correcta. –

+0

Verificando que esta solución funciona, pero vea la [nota en los documentos] (https://docs.djangoproject.com/en/1.10/ref/forms/fields/#booleanfield). Necesita establecer required = False en el campo. – grokpot

9

En Django 1.6, los siguientes trabajó 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.')    
     ])} 
Cuestiones relacionadas