9

Let me start with usual - I'm new to both Python & Flask. Before posting this question (my first ever here) I have spent number of hours searching and experimenting, unfortunately with no luck so far.

I am building web form where user can define firewall rules, which subsequently get recorded in the database. I am at the validation stage and I came up to a wall here... hopefully someone will be able to help me out.

My (simplified here) form has 2 fields - src_ip and dst_ip:

class FirewallRule(Form)
    src_ip = StringField('Source IP')
    dst_ip = StringField('Destination IP')

and my validation requirements are:

  1. At least 1 field must be filled (both are also fine)
  2. Fields that are filled must contain valid IP address

wtforms.validators.IPAddress() and custom validation function seems to be my friend, but I am struggling to find a way to plug them together.

Essentially I am trying to build conditional validation:

  1. If not (src_ip OR dst_ip); return False
  2. If src_ip AND src_ip not valid IP address; return False
  3. If dst_ip AND dst_ip not valid IP address; return False
  4. Return True

Obviously I would like to re-use IPAddress() [or generally any of the built-in validators] rather then write my own.

I am sure someone must have done it before.. unfortunately I could not find any pointers in the right direction.

Thanks in advance.

2
  • You could try to reload validate method of the form and raise ValidationError when needed. Commented Apr 17, 2015 at 16:10
  • @dizballanze this would let me ensure that at least one of the fields is filled, but I would not be able to use validators to validate input Commented Apr 17, 2015 at 20:20

1 Answer 1

22

You are missing one very useful validator: Optional. This validator allows you to say that a field can be empty, but if it isn't empty then other validators should be used.

The part about having at least one of the fields filled out I would do with a custom validation method, I don't think there is any stock validators that can help with that.

So it would be something like this:

class FirewallRule(Form)
    src_ip = StringField('Source IP', validators=[Optional(), IPAddress()])
    dst_ip = StringField('Destination IP', validators=[Optional(), IPAddress()])

    def validate(self):
        if not super(FirewallRule, self).validate():
            return False
        if not self.src_ip.data and not self.dst_ip.data:
            msg = 'At least one of Source and Destination IP must be set'
            self.src_ip.errors.append(msg)
            self.dst_ip.errors.append(msg)
            return False
        return True

If you want to avoid a custom validation function, then consider that it would be fairly easy to create a validator class to check that at least one of a list of fields are set. You can look at the implementation of the EqualTo validator for inspiration if you would like to follow this route.

Sign up to request clarification or add additional context in comments.

3 Comments

Many thanks Miguel. I was aware of Optional(), but I had no idea that bundling it with another validator will have such effect - this is clever!!
Thanks Miguel for the answer. It helped me. but I have one issue. I have 2 fields, StringField and BooleanField. one of them should be opted. Your solution worked for me but I am unable to set the BooleanField to error(error message is showing fine for StringFeild but not for BooleanField). I mean I am unable to append error to that field. any workaround for that? Any help would be great :)
@Pradeepb you should be able to set errors on any fields. Are you sure the problem isn't on the way you render the checkbox? The HTML that you render for the checkbox must include error messages, like you do for the text field.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.