Comment rendre un champ conditionnellement optionnel dans WTForms?

ma validation de formulaire fonctionne presque complet, je viens d'avoir 2 cas, je ne sais pas exactement comment résoudre: 1) le champ de mot de passe devrait être exigé bien sûr, mais je fournis également la possibilité de se connecter avec google ou compte facebook via OAuth et puis nom est rempli au préalable, mais je supprime le champ de mot de passe complètement du formulaire est il ya un utilisateur (google) ou un objet utilisateur facebook:

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

donc pour ces utilisateurs qui sont déjà connectés et le champ mot de passe n'a pas de sens, j'ai besoin d'un peu de logique pour faire conditionnelle facultative. Je pensais que je pourrais avoir une variable pour logged_in + une méthode dans ma classe de formulaire comme ceci:

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

est-ce que la commande validate_password ci-dessus fonctionnera pour obtenir l'effet désiré? Y a-t-il un autre meilleur moyen? Une autre façon dont je pourrais penser est d'avoir 2 classes de forme différentes et dans http post j'instanciate la classe de forme il devrait être:

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

I il faut également une validation conditionnelle pour le champ Catégorie, lorsqu'une certaine catégorie est sélectionnée, alors plus de choix apparaissent et ceux-ci ne devraient avoir une validation que pour une certaine catégorie de base, par exemple. l'utilisateur sélectionne "voiture" et puis via Ajax peut choisir les données d'immatriculation et le kilométrage pour la voiture et ces champs sont nécessaires étant donné que la voiture de catégorie a été sélectionnée.

donc il pourrait s'agir de deux questions, mais les deux cas se rapportent à la façon dont je peux rendre un champ "conditionally optional" ou "conditionally optional" requis."

Mon formulaire ressemble à ce

enter image description here

et pour un utilisateur connecté Je pré-remplir le nom et l'adresse e-mail et le champ pasword n'est tout simplement pas utilisé, de sorte que le champ Mot de passe ne correspond ni étant" optionnel "ni" requis", il aurait besoin de quelque chose comme" conditionnellement optionnel "ou" conditionnellement requis."

enter image description here

Merci pour tout une réponse ou un commentaire

20
demandé sur Niklas Rosencrantz 2011-12-11 14:08:33

3 réponses

Je ne suis pas sûr que cela corresponde à vos besoins, mais j'ai utilisé un validateur personnalisé RequiredIf sur les champs avant, ce qui rend un champ obligatoire si un autre champ a une valeur dans le formulaire... par exemple, dans un datetime-et-timezone scénario, je peux faire le champ timezone nécessaire d'avoir une valeur si l'utilisateur a entré un datetime.

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)

le constructeur prend le nom de l'autre champ qui déclenche ce champ requis, comme:

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

cela pourrait être un bon point de départ pour mettre en œuvre le genre de logique dont vous avez besoin.

56
répondu dcrosta 2011-12-11 13:56:19

j'ai trouvé cette question utile et basé sur la réponse de @dcrosta j'ai créé un autre validateur qui est facultatif. L'avantage est que vous pouvez le combiner avec d'autres validateurs wtforms. Voici mon validateur optionnel qui vérifie un autre champ. Parce que j'avais besoin de vérifier la valeur de l'autre champ contre une certaine valeur, j'ai ajouté une coutume vérifier la valeur:

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)
4
répondu Mehdi Sadeghi 2014-08-20 10:22:31

la réponse de @dcrosta est excellente, mais je pense que certaines choses ont changé dans wtforms depuis cette réponse. Hériter de DataRequired ajoute un attribut required au champ de formulaire, de sorte que le validateur conditionnel ne soit jamais appelé. J'ai fait un changement mineur à la classe de @dcrosta qui fonctionne avec les formulaires WT 2.1. Cela ne fait que surcharger field_flags de sorte que la validation du navigateur n'est pas faite.

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
        - /q/how-to-make-a-field-conditionally-optional-in-wtforms-27966/"""
    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)

une solution plus idéale permettrait de faire la validation dans le navigateur, comme le comportement actuel de DataRequired .

3
répondu dennisobrien 2017-05-20 00:39:57