2011-12-11 20 views
18

La validación de mi formulario está casi terminada, solo tengo 2 casos que no sé exactamente cómo resolver: 1) El campo de contraseña debe ser requerido por supuesto, pero también brindo la posibilidad de iniciar sesión con la cuenta de google o facebook a través de OAuth y después el nombre se llena previamente pero me quite el campo de la contraseña por completo de la forma es que hay un usuario (Google) o un objeto de usuario de Facebook:¿Cómo hacer un campo condicionalmente opcional en WTForms?

<tr><td> 
    <br />  {% if user or current_user %} {% else %} 

    <div class="labelform"> 
    {% filter capitalize %}{% trans %}password{% endtrans %}{% endfilter %}: 
    </div> 
     </td><td> <div class="adinput">{{ form.password|safe }}{% trans %}Choose a password{% endtrans %}</div>{% endif %} 

    </td></tr> 

Así que para estos usuarios que ya han iniciado sesión en el campo de contraseña no tiene sentido, necesito un poco de lógica para hacer que ese campo sea condicionalmente opcional. Estaba pensando que podría tener una variable de logged_in + un método en mi clase de la forma como este:

class AdForm(Form): 
    logged_in = False 
    my_choices = [('1', _('VEHICLES')), ('2', _('Cars')), ('3', _('Bicycles'))] 
    name = TextField(_('Name'), [validators.Required(message=_('Name is required'))], widget=MyTextInput()) 
    title = TextField(_('title'), [validators.Required(message=_('Subject is required'))], widget=MyTextInput()) 
    text = TextAreaField(_('Text'),[validators.Required(message=_('Text is required'))], widget=MyTextArea()) 
    phonenumber = TextField(_('Phone number')) 
    phoneview = BooleanField(_('Display phone number on site')) 
    price = TextField(_('Price'),[validators.Regexp('\d', message=_('This is not an integer number, please see the example and try again')),validators.Optional()]) 
    password = PasswordField(_('Password'),[validators.Optional()], widget=PasswordInput()) 
    email = TextField(_('Email'), [validators.Required(message=_('Email is required')), validators.Email(message=_('Your email is invalid'))], widget=MyTextInput()) 
    category = SelectField(choices = my_choices, default = '1') 

    def validate_name(form, field): 
     if len(field.data) > 50: 
      raise ValidationError(_('Name must be less than 50 characters')) 

    def validate_email(form, field): 
     if len(field.data) > 60: 
      raise ValidationError(_('Email must be less than 60 characters')) 

    def validate_price(form, field): 
     if len(field.data) > 8: 
      raise ValidationError(_('Price must be less than 9 integers')) 

    def validate_password(form, field): 
     if not logged_in and not field: 
      raise ValidationError(_('Password is required')) 

¿Funcionará validate_password anterior para lograr el efecto deseado? ¿Hay alguna otra forma mejor? Otra forma de lo que podía pensar es tener 2 diferentes clases de formulario y en http post que instanciar la clase de formulario que debe ser:

def post(self): 
    if not current_user: 
     form = AdForm(self.request.params) 
    if current_user: 
     form = AdUserForm(self.request.params) 

También necesito la validación condicional para el campo de categoría, cuando una determinada categoría se selecciona a continuación más aparecen las opciones y estas deben tener validación solo para una cierta categoría base, por ej. el usuario selecciona "Coche" y luego a través de Ajax puede elegir los datos de registro y el kilometraje del automóvil y estos campos son obligatorios dado que se seleccionó la categoría Coche.

Así que pueden ser dos preguntas, pero ambos casos se relacionan con cómo puedo hacer que un campo sea "condicionalmente opcional" o "condicionalmente requerido".

Mi forma se parece a esto

enter image description here

Y para un usuario conectado I pre-rellenar el nombre y dirección de correo electrónico y el campo pasword simplemente no se utiliza, por lo que el campo de contraseña no se ajusta a ser "opcional" ni "requerido", necesitaría algo como "condicionalmente opcional" o "condicionalmente requerido".

enter image description here

Gracias por cualquier respuesta o comentario

Respuesta

53

no estoy seguro de esto bastante adapte a sus necesidades, pero yo he usado un validador RequiredIf personalizada en los campos antes, lo que hace que un campo obligatorio si otro campo tiene un valor en la forma ... por ejemplo, en un escenario de fecha y hora y zona horaria, puedo hacer que el campo de zona horaria requiera tener un valor si el usuario ha ingresado una fecha y hora.

class RequiredIf(Required): 
    # a validator which makes a field required if 
    # another field is set and has a truthy value 

    def __init__(self, other_field_name, *args, **kwargs): 
     self.other_field_name = other_field_name 
     super(RequiredIf, self).__init__(*args, **kwargs) 

    def __call__(self, form, field): 
     other_field = form._fields.get(self.other_field_name) 
     if other_field is None: 
      raise Exception('no field named "%s" in form' % self.other_field_name) 
     if bool(other_field.data): 
      super(RequiredIf, self).__call__(form, field) 

El constructor toma el nombre del otro campo que dispara haciendo de este campo requiere, como:

class DateTimeForm(Form): 
    datetime = TextField() 
    timezone = SelectField(choices=..., validators=[RequiredIf('datetime')]) 

Esto podría ser un buen punto de partida para la realización del tipo de lógica que necesita.

+2

¿Cuál es la licencia para usar su fragmento de código? –

+1

@Mehdi: http://meta.stackexchange.com/questions/12527/do-i-have-to-worry-about-copyright-issues-for-code-posted-on-stack-overflow – brandones

+0

Awesome³! Funciona muy bien! – Roman

4

Encontré esta pregunta útil y, de acuerdo con la respuesta de @dcrosta, creé otro validador que es opcional. El beneficio es que puede combinarlo con otros validadores de wtforms. Aquí está mi validador opcional que verifica otro campo.Debido a que tenía que comprobar el valor del otro campo en contra de algunas cierto valor añadí un cheque por el valor de encargo:

class OptionalIfFieldEqualTo(wtf.validators.Optional): 
    # a validator which makes a field optional if 
    # another field has a desired value 

    def __init__(self, other_field_name, value, *args, **kwargs): 
     self.other_field_name = other_field_name 
     self.value = value 
     super(OptionalIfFieldEqualTo, self).__init__(*args, **kwargs) 

    def __call__(self, form, field): 
     other_field = form._fields.get(self.other_field_name) 
     if other_field is None: 
      raise Exception('no field named "%s" in form' % self.other_field_name) 
     if other_field.data == self.value: 
      super(OptionalIfFieldEqualTo, self).__call__(form, field) 
2

La respuesta de @dcrosta es grande, pero creo que algunas cosas han cambiado en wtforms desde esta respuesta . Heredar de DataRequired agrega un atributo required al campo de formulario, por lo que nunca se llama al validador condicional. Hice un cambio menor en la clase de @dcrosta que funciona con wtforms 2.1. Esto solo anula field_flags para que la validación del navegador no se realice.

from wtforms.validators import DataRequired 


class RequiredIf(DataRequired): 
    """Validator which makes a field required if another field is set and has a truthy value. 

    Sources: 
     - http://wtforms.simplecodes.com/docs/1.0.1/validators.html 
     - http://stackoverflow.com/questions/8463209/how-to-make-a-field-conditionally-optional-in-wtforms 

    """ 
    field_flags = ('requiredif',) 

    def __init__(self, other_field_name, message=None, *args, **kwargs): 
     self.other_field_name = other_field_name 
     self.message = message 

    def __call__(self, form, field): 
     other_field = form[self.other_field_name] 
     if other_field is None: 
      raise Exception('no field named "%s" in form' % self.other_field_name) 
     if bool(other_field.data): 
      super(RequiredIf, self).__call__(form, field) 

Una solución más ideal sería llegar a hacer la validación en el navegador, al igual que el comportamiento actual de DataRequired.

Cuestiones relacionadas