How to make a field conditionally optional in WTForms?

前端 未结 3 922
渐次进展
渐次进展 2020-12-02 09:46

My form validation is working nearly complete, I just have 2 cases I don\'t know exactly how to solve: 1) The password field should be required of course but I also provide

相关标签:
3条回答
  • 2020-12-02 10:01

    The answer from @dcrosta is great, but I think some things have changed in wtforms since this answer. Inheriting from DataRequired adds a required attribute to the form field, so the conditional validator never gets called. I made a minor change to the class from @dcrosta that works with wtforms 2.1. This only over-rides field_flags so that browser validation is not done.

    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)
    

    A more ideal solution would manage to do the validation in the browser, like the current behavior of DataRequired.

    0 讨论(0)
  • 2020-12-02 10:02

    I'm not sure this quite fits your needs, but I've used a RequiredIf custom validator on fields before, which makes a field required if another field has a value in the form... for instance, in a datetime-and-timezone scenario, I can make the timezone field required to have a value if the user has entered a 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)
    

    The constructor takes the name of the other field that triggers making this field required, like:

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

    This could be a good starting point for implementing the sort of logic you need.

    0 讨论(0)
  • 2020-12-02 10:09

    I found this question helpful and based on the answer of @dcrosta I created another validator which is optional. The benefit is that you can combine it with other wtforms validators. Here is my optional validator which checks another field. Because I needed to check the value of the other field against some certain value I added a custom check for value:

    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)
    
    0 讨论(0)
提交回复
热议问题