简体   繁体   中英

Trouble with Flask wtforms validators (forms inside of form)

I have been trying to incorporate wtforms validators inside 2 forms I have on my index.html(this is a Uni assignment). Everything worked well before I did anything, but security was very bad. After I have inserted some wtform validators, everything works OK. But usability is quite bad. If I get an error whilst filling out one of the forms, I get error messages not only in the form I was writing stuff in, but also in the other separate form on index.html.

I suspect it has something with the way the assignment is set up. Like I said, I have 2 forms on my index.html. In a separate python file, where all the forms are configured, there is the following setup (where LoginForm and RegisterForm are the two forms on index.html):

class LoginForm(FlaskForm):
    #more code here

class RegisterForm(FlaskForm):
    #more code here

class IndexForm(FlaskForm):
    login = FormField(LoginForm)
    register = FormField(RegisterForm)

My first thought was to just delete the IndexForm code (and obviously update the code everywhere else where it was needed). I can´t see why the class IndexForm has to wrap the other 2. But that didn´t work out. So I suspect there is a reason why it´s set up the way it is. But how can I make RegisterForm and LoginForm behave such that a validation error in one of them, doesn´t trigger error messages in the other? I have inserted more verbose code below, if that could be of any help.

forms.py

from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField, FormField, TextAreaField, FileField
from wtforms.fields.html5 import DateField
from wtforms.validators import InputRequired, Length, EqualTo, NoneOf

# defines all forms in the application, these will be instantiated by the template,
# and the routes.py will read the values of the fields
# TODO: Add validation, maybe use wtforms.validators??
# TODO: There was some important security feature that wtforms provides, but I don't remember what; implement it

#invalidInput = [ADD THINGS HERE]

class LoginForm(FlaskForm):
    username = StringField('Username', render_kw={'placeholder': 'Username'}, validators=[InputRequired()])
    password = PasswordField('Password', render_kw={'placeholder': 'Password'}, validators=[InputRequired()])
    remember_me = BooleanField('Remember me') # TODO: It would be nice to have this feature implemented, probably by using cookies
    submit = SubmitField('Sign In')

class RegisterForm(FlaskForm):
    first_name = StringField('First Name', render_kw={'placeholder': 'First Name'}, validators=[InputRequired(), NoneOf(invalidInput, message="Invalid input")])
    last_name = StringField('Last Name', render_kw={'placeholder': 'Last Name'}, validators=[InputRequired()])

    username = StringField('Username', render_kw={'placeholder': 'Username'}, validators=[
                           InputRequired(), Length(min=5, max=50, message="Must be between 5 and 50 characters")])
    password = PasswordField('Password', render_kw={'placeholder': 'Password'}, validators=[
                             InputRequired(), Length(min=8, max=50, message="Must be between 8 and 50 characters"), EqualTo('confirm_password', message='Passwords must match')])
    confirm_password = PasswordField('Confirm Password', render_kw={'placeholder': 'Confirm Password'}, validators=[
                                     InputRequired(), Length(min=8, max=50, message="Must be between 8 and 50 characters")])
    submit = SubmitField('Sign Up')

class IndexForm(FlaskForm):
    login = FormField(LoginForm)
    register = FormField(RegisterForm)

routes.py

from app import app, query_db
from app.forms import IndexForm, PostForm, FriendsForm, ProfileForm, CommentsForm
from datetime import datetime
import os
#############################
from flask_wtf import FlaskForm
from wtforms import (StringField, PasswordField, SubmitField, TextAreaField, IntegerField, BooleanField, RadioField)
from wtforms.validators import InputRequired, Length

# this file contains all the different routes, and the logic for communicating with the database

# home page/login/registration
@app.route('/', methods=['GET', 'POST'])
@app.route('/index', methods=['GET', 'POST'])
def index():
    form = IndexForm()
    
    if form.login.validate_on_submit() and form.login.is_submitted() and form.login.submit.data:
        
        user = query_db('SELECT * FROM Users WHERE username="{}";'.format(form.login.username.data), one=True)
        print("user is ", user)
        if user == None:
            flash('Sorry, this user does not exist!')
        elif user['password'] == form.login.password.data:
            return redirect(url_for('stream', username=form.login.username.data))
        else:
            flash('Sorry, wrong password!')

    elif form.register.validate_on_submit() and form.register.is_submitted() and form.register.submit.data:
        
        flash("New user registered!")
        query_db('INSERT INTO Users (username, first_name, last_name, password) VALUES("{}", "{}", "{}", "{}");'.format(form.register.username.data, form.register.first_name.data,
         form.register.last_name.data, form.register.password.data))
        print(form.register.username.data)
        print(form.register.password.data)
        return redirect(url_for('index'))
    
    
    
    return render_template('index.html', title='Welcome', form=form)

index.html

{% import "bootstrap/wtf.html" as wtf %}
{% block content %}    
<div class="jumbotron jumbotron-fluid">
    <div class="container">
        <h1 class="display-4">Social Insecurity</h1>
        <p class="lead">The social network for the insecure&trade;</p>
    </div>
</div>
<div class="container-fluid">
    <div class="row">
        <div class="col-sm-12 col-lg-6">
            <div class="card text-center">
                <div class="card-header">
                    Sign In
                </div>
                <div class="card-body">
                    <h5 class="card-title">Access an existing profile</h5>
                    <form action="" method="POST" novalidate>
                        {{ wtf.form_field(form.login.username) }}
                        {{ wtf.form_field(form.login.password) }}
                        {{ wtf.form_field(form.login.remember_me) }}
                        {{ wtf.form_field(form.login.submit, class="btn btn-primary") }}
                    </form>
                </div>
            </div>
        </div>
        <div class="col-sm-12 col-lg-6">
            <div class="card text-center">
                <div class="card-header">
                    Register
                </div>
                <div class="card-body">
                    <h5 class="card-title">Create a new profile</h5>
                    <form action="", method="POST" novalidate>
                        {{ wtf.form_field(form.register.csrf_token) }}
                        {{ wtf.form_field(form.register.first_name) }}
                        {{ wtf.form_field(form.register.last_name) }}
                        {{ wtf.form_field(form.register.username) }}
                        {{ wtf.form_field(form.register.password) }}
                        {{ wtf.form_field(form.register.confirm_password) }}
                        {{ wtf.form_field(form.register.submit, class="btn btn-primary") }}
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
{% endblock %}```

Solved it by removing the validators from LoginForm in forms.py. No need to validate these fields, if I have already validated them when creating a new user.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM