Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Flask Admin Custom Form Validation for Multiple Fields?

I have been intending to create a custom form validation logic that's based on multiple field values (in my case, 2 fields to ensure date range data integrity is ensured, I.E. start_time < end_time). However, flipping through the documentation on flask admin site, I couldn't find anywhere to do this sort of stuff. I am aware of that you can pretty trivially pass a list of validation functions to validators argument for form_args property in a subclass of a BaseModelView class, but again, that's per-field validation not exactly what I want.

So my question is this: how does one validate multiple fields together at once?

Also, I don't see any pre-save hook event function to tap into do do this. I am aware of on_model_change but then it's a post-save hook, it would defeat the purpose of validation to put the validation in there. What would be the appropriate the way go about doing pre-save actions?

like image 836
Devy Avatar asked Jul 27 '15 21:07

Devy


2 Answers

So after experimenting and trying out a few different approaches, the way I did multiple form field validation is still to peg along on_model_change I know it says the event hook is called after the changes have been made - however, since it's been wrapped in a transaction, one can raise any exception to roll back the transaction.

Here is my sample code to make it work.

from flask.ext.admin.form import rules
from wtforms import validators

class TimeWindowView(LoggedInView):
    column_filters = ('scheduled_start', 'scheduled_end')
    form_create_rules = [
        rules.Field('scheduled_start'),
        rules.Field('scheduled_end'),
    ]

    def on_model_change(self, form, model, is_created):
        # if end date before start date or end date in the past, flag them invalid
        if (form.scheduled_end.data <= form.scheduled_start.data or
            form.scheduled_end.data <= datetime.datetime.utcnow()):
            raise validators.ValidationError('Invalid schedule start and end time!')
        else:
            super().on_model_change(form, model, is_created)
like image 192
Devy Avatar answered Sep 22 '22 23:09

Devy


You can introduce custom form validation code to your flask admin model views by using inheritance and a custom "validate_form" method that incorporates your validation code before calling the parent "validate form".

If your validation logic finds a problem, your validate_form should display an appropriate error message and return False, otherwise it should continue by running the original flask admin validation form code.

from flask_admin.contrib.sqla import ModelView
from flask import flash

class MyModelView(ModelView):
    """ My model admin model view """

    def validate_form(self, form):
        """ Custom validation code that checks dates """
        if form.start_time.data > form.end_time.data:
            flash("start time cannot be greater than end time!")
            return False
        return super(MyModelView, self).validate_form(form)

This is a much more natural place to do form validation than at the change_model_model method, which shouldn't be concerned with model logic, not form validation logic. Also, note we don't need to use an exception and rely on reversing the transaction. We simply catch the error before any transaction has occurred, flash an error message and gracefully return a "False" state.

Relevant links:

flask admin documentation

flask admin source code

like image 28
Angelos Avatar answered Sep 22 '22 23:09

Angelos