2

Form classes are intended (IMO) for submitted data against rules. For example: are passwords equal, is end date later than start date.

submitted data--->|Form|

Is it okay for Form classes to validate submitted data against data retrieved from a database as well? This seems like a responsibility issue, the Form class should responsible for validating and cleaning the submission alone, and checking against the DB belongs outside the class.

submitted data--->|Form|<---data from DB


Here is my example in WTForms in Python: it checks if the user id is an integer, then queries the DB to verify that it exists.

class ClientForm(Form):
    name = StringField(validators=[DataRequired(message="Invalid value")])
    user = IntegerField(validators=[DataRequired(message="Invalid value")])
    zone = IntegerField(validators=[AnyOf([i[0] for i in ZONES], message="Invalid value")])

    #validate user as real
    def validate_user(form, field):
        user = db.session.query(User).filter(User.id==form.user.data).first()
        if not user:
            raise ValidationError('Invalid user')

The upside of adding this check to the form is convenience, WTForms handles all aspects of errors, even rendering them:

form = ClientForm(post_data)
if not form.validate():
    # render the form again with errors highlighted
    return render("client_registration_form.html", form=form)
else:
    return render("success.html")
5
  • 2
    I'm just wondering - why do you need to validate your database data? It should have been validated before it was stored...
    – Jules
    Commented Sep 3, 2015 at 10:59
  • 1
    The database needs to be private or the people with access to the database have to know what they're doing. You can't check input from the user and input from the database or you'll go cross-eyed.
    – Neil
    Commented Sep 3, 2015 at 14:27
  • @Jules, I am taking the database as true. I am validating the submitted data. Commented Sep 3, 2015 at 15:11
  • @Neil, not sure I understand which issues from database not being private. Commented Sep 3, 2015 at 15:14
  • Your program inserts the data into the database, so assuming you're not out to trick yourself, the data coming from the database should be fine. The database should never be a means by which a user should change the data. So if you tell your client to not touch the database, and he touches it anyway, improper functioning of the program as a consequence is not your problem. And, if he doesn't touch the database, you should not expect anything other than what your program inserts.
    – Neil
    Commented Sep 4, 2015 at 6:32

2 Answers 2

1

By referencing your database directly, and especially by grabbing it out of a global, you are tightly coupling your presentation layer with your persistence layer. We should instead approach this problem with an eye to the SOLID principles.

Instead of reaching into a global object to get the database connection, we should inject that dependency in to the form validator. That way, we can depend on the abstraction of a database rather than the concretion of a piece of global state. The code becomes more flexible and testable since the dependency can be swapped out.

The better way to achieve this would be to create an intermediary object to decouple the form validation from the database completely. This intermediary object would have the database connection injected into it, then it would be injected into the form validator. This would allow the form validator to have a flexible dependency. It might look like:

class UserIDExists:
    def __init__(self, db):
        self["db"] = db

    def check(self, user_id):
        user = db.session.query(User).filter(User.id == user_id).first()
        return bool(user)

Then your WTForms class would use the check method to determine if it should raise or not.

But there is an even better way. Instead of just creating an arbitrary class, we could create a class that is a custom WTForms validator. We would still inject it, but it would integrate in a much cleaner and more seamless way with the rest of the validators you already use.

0

I think it's fine to use WTForms to validate data not directly submitted by a user. It seems very strange to validate data from your database: the database and DAL should have validated it already.

It's not unreasonable to use WTForms to validate a combination of user-submitted data and data from the database. Still, for an interactive form, I'd prefer the user see a form which by its very structure prevents the entry of invalid data, based on the contents of the database. Probably, sometimes it is not possible or practical.

I can easily see using WTForms to validate data coming from e.g. external systems which are not form submissions, like parsed input files.

1
  • I am not validating the database itself.I am validating the submitted data. Commented Sep 3, 2015 at 15:19

Not the answer you're looking for? Browse other questions tagged or ask your own question.