Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using flask wtforms validators without using a form

Tags:

python

flask

I'm receiving user registration data from an iOS application and I'd like to use the validators that come with wtforms to make sure the email and password are acceptable. However, I'm not using a flask form since users are inputting the data from iOS textfields. Is it possible to check the incoming JSON data with the wtforms validators?

@auth.route('/register', methods=['POST'])
def register():
    try:
        user = User.register_fromJSON(request.json)

        email_success = validate_email(user)
        username_success = validate_username(user)

        if email_success == 1 and username_success == 1:
            db.session.add(user)
            db.session.commit()
            return jsonify({'Success': 1})
        else:
            return jsonify({'Failure': 0})

    except Exception:
        return jsonify({'Failure': 0})

def validate_email(user):
    if User.query.filter_by(email=user.email).first() == None:
        return 1
    else:
        return 0

def validate_username(user):
    if User.query.filter_by(username=user.username).first() == None:
        return 1
    else:
        return 0

EDIT

I created a Registration form:

class RegistrationForm(Form):
    email = StringField('Email', validators=[Required(), Length(1,64), Email()])
    username = StringField('Username', validators=[Required(), Length(1, 64), Regexp('^[A-Za-z][A-Za-z0-9_.]*$', 0, 'Usernames must have only letters, 'numbers, dots or underscores')])
    password = PasswordField('Password', validators=[Required()])


    def validate_email(self, field):
        if User.query.filter_by(email=field.data).first():
            print("Email already registered.")
            raise ValidationError('Email already registered.')

    def validate_username(self, field):
        if User.query.filter_by(username=field.data).first():
            print("Username already in use.")
            raise ValidationError('Username already in use.')

registration function has been updated to:

@auth.route('/register', methods=['POST'])
def register():
    try:
        data = MultiDict(mapping=request.json)
        form = RegistrationForm(data)

        if form.validate():
            user = User.register_fromJSON(request.json)
            db.session.add(user)
            db.session.commit()
            return jsonify({'Success': 1})
        else:
            return jsonify({'Success': 2})

    except Exception:
        return jsonify({'Success': 3})
like image 331
Brosef Avatar asked Aug 18 '15 01:08

Brosef


People also ask

Should I use WTForms?

WTForms are really useful it does a lot of heavy lifting for you when it comes to data validation on top of the CSRF protection . Another useful thing is the use combined with Jinja2 where you need to write less code to render the form. Note: Jinja2 is one of the most used template engines for Python.

Which of the following validators can be used to compare values of two form fields?

You can perform this type of form validation by using the CompareValidator control. To compare two dates, you need to set the ControlToValidate, ControlToCompare, Operator, and Type properties of the CompareValidator control.


2 Answers

Yes, this is entirely possible - the wtforms.Form constructor takes any MultiDict like interface (it just needs to have getlist), so you can just create an instance of werkzeug.datastructures.MultiDict from your JSON:

data = MultiDict(mapping=request.json)
form = YourForm(data)
if form.validate():
    # Data is correct

(assuming the field names match) and things will just work.

like image 109
Sean Vieira Avatar answered Oct 07 '22 03:10

Sean Vieira


Here's a little utility called Flask-Inputs that I'm working on to solve this. The goal is to allow all incoming data (forms, queries, headers, etc) to be validated with wtform validators.

Here's how validation would work with your data:

from flask_inputs import Inputs
from wtforms.validators import Length, Email, ValidationError


class RegisterInputs(Inputs):
    json = {
        'email': [Email(), unique_email],
        'username': [Length(min=3, max=15), unique_username]
    }

def unique_email(form, field):
    if User.query.filter_by(email=field.data).first():
        raise ValidationError('Email is already registered.')

def unique_username(form, field):
    if User.query.filter_by(username=field.data).first():
        raise ValidationError('Username is already registered.')


@auth.route('/register', methods=['POST'])
def register():
    inputs = RegisterInputs(request)

    if inputs.validate():
        user = User.register_fromJSON(request.json)

        db.session.add(user)
        db.session.commit()

        return jsonify(success=1)
    else:
        return jsonify(failure=0, errors=inputs.errors)
like image 22
nathancahill Avatar answered Oct 07 '22 02:10

nathancahill