1

I'm wondering where should I put a validation form which accessing database. Basically I will need user to enter item_type and I want to check first i the item_type has exist in database.

There are 3 options:

  1. In the database model, I have ItemType class and I put function add() which will check if existing item has exist or not

  2. In view, so in the route of the page, from wtforms form.validate_on_submit(), I do a check to get data from database, and if exist I will put error in here

  3. In wtforms validate(), adding extra validation after default validation of the Form class

I've seen people using number 2 and 3, but not sure which one is the best. The error message that I want will also need to display it on the specific field of the form (this is achieveable by method 2 and 3 since they have reference to the form field) but then again since it is related to accessing database, maybe it is better to put everything regarding database access to model functions?

andiwin
  • 1,552
  • 3
  • 14
  • 27

1 Answers1

2

In my opinion, if it comes from a form then it should be validated on that form and then raise an error for that specific field when invalid. See the example bellow:

class SigninForm(Form):
    """Form for signin"""
    email = StringField('Email',
                        validators=[
                            DataRequired("Email shouldn't be empty."),
                            Email('Email format is not correct.')
                        ])

    password = PasswordField('Password',
                             validators=[DataRequired("Password shouldn't be empty.")])

    def validate_email(self, field):
        """ 
            verify if account exists and if not raise an error in
            that field. 
        """
        user = User.query.filter(User.email == self.email.data).first()
        if not user:
            raise ValueError("Account doesn't exist.")

    def validate_password(self, field):
        """ 
            Verify if password is valid and if not raise an error in
            that field. 
        """
        if self.email.data:
            user = User.query.filter(User.email == self.email.data).first()
            if not user or not user.check_password(self.password.data):
                raise ValueError('Password is not correct.')
            else:
                self.user = user

The view function for this example:

@app.route('/signin', methods=['GET', 'POST'])
def signin():
    """Signin"""
    form = SigninForm()
    if form.validate_on_submit():
        # sign in function to register user into a session
        signin_user(form.user)
        return redirect(url_for('site.index'))
    return render_template('account/signin/signin.html', form=form)
Filipe Amaral
  • 1,683
  • 1
  • 14
  • 15
  • 1
    If you're not passing `validate_email` and `validate_password` into each respective Field constructor as custom validators, how/when are they being called? Is there something auto-magically happening as a result of your method naming plus inheriting the WTForm Form? – afilbert Jan 03 '17 at 21:26