WTForms: two forms on one page?

I have a dynamic web page that needs to process two forms: a form and a registration form . I use WTForms to process two forms, but I have problems working with it, since both forms appear on the same page.

The following is the login form code for my web page:

PYTHON: class Login(Form): login_user = TextField('Username', [validators.Required()]) login_pass = PasswordField('Password', [validators.Required()]) @application.route('/index', methods=('GET', 'POST')) def index(): l_form = Login(request.form, prefix="login-form") if request.method == 'POST' and l_form.validate(): check_login = cursor.execute("SELECT * FROM users WHERE username = '%s' AND pwd = '%s'" % (l_form.login_user.data, hashlib.sha1(l_form.login_pass.data).hexdigest())) if check_login == True: conn.commit() return redirect(url_for('me')) return render_template('index.html', lform=l_form) HTML: <form name="lform" method="post" action="/index"> {{ lform.login_user }} {{ lform.login_pass }} <input type="submit" value="Login" /> </form> 

The following is the code for the register form of my web page:

 PYTHON: class Register(Form): username = TextField('Username', [validators.Length(min=1, max = 12)]) password = PasswordField('Password', [ validators.Required(), validators.EqualTo('confirm_password', message='Passwords do not match') ]) confirm_password = PasswordField('Confirm Password') email = TextField('Email', [validators.Length(min=6, max=35)]) @application.route('/index', methods=('GET','POST')) def register(): r_form = Register(request.form, prefix="register-form") if request.method == 'POST' and r_form.validate(): check_reg = cursor.execute("SELECT * FROM users WHERE username = '%s' OR `e-mail` = '%s'" % (r_form.username.data, r_form.email.data)) if check_reg == False: cursor.execute("INSERT into users (username, pwd, `e-mail`) VALUES ('%s','%s','%s')" % (r_form.username.data, hashlib.sha1(r_form.password.data).hexdigest(), check_email(r_form.email.data))) conn.commit() return redirect(url_for('index')) return render_template('index.html', rform=r_form) HTML: <form name="rform" method="post" action="/index"> {{ rform.username }} {{ rform.email }} {{ rform.password }} {{ rform.confirm_password }} <input type="submit" value="Register /> </form> 

I get the following error when I go and load a web page:

  Traceback (most recent call last): File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\app.py", line 1836, in __call__ return self.wsgi_app(environ, start_response) File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\app.py", line 1820, in wsgi_app response = self.make_response(self.handle_exception(e)) File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\app.py", line 1403, in handle_exception reraise(exc_type, exc_value, tb) File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\app.py", line 1817, in wsgi_app response = self.full_dispatch_request() File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\app.py", line 1477, in full_dispatch_request rv = self.handle_user_exception(e) File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\app.py", line 1381, in handle_user_exception reraise(exc_type, exc_value, tb) File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\app.py", line 1475, in full_dispatch_request rv = self.dispatch_request() File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\app.py", line 1461, in dispatch_request return self.view_functions[rule.endpoint](**req.view_args) File "C:\Users\HTVal_000\Desktop\innoCMS\main.py", line 36, in index return render_template('index.html', lform=l_form) File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\templating.py", line 128, in render_template context, ctx.app) File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\flask\templating.py", line 110, in _render rv = template.render(context) File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\jinja2\environment.py", line 969, in render return self.environment.handle_exception(exc_info, True) File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\jinja2\environment.py", line 742, in handle_exception reraise(exc_type, exc_value, tb) File "C:\Users\HTVal_000\Desktop\innoCMS\templates\default\index.html", line 52, in top-level template code {{ rform.username }} File "C:\Users\HTVal_000\Desktop\innoCMS\virtualenv\lib\site-packages\jinja2\environment.py", line 397, in getattr return getattr(obj, attribute) UndefinedError: 'rform' is undefined 

From what I understand, there is a conflict between the forms, because according to the trace:

 return render_template('index.html', lform=l_form) 

It returns the following error:

 UndefinedError: 'rform' is undefined 

When the script sees:

 {{ rform.username }} {{ rform.email }} {{ rform.password }} {{ rform.confirm_password }} 

But he completely ignores:

 {{ lform.login_user }} {{ lform.login_pass }} 

This can be a bit confusing, the workloads also confuse me, and I hope someone has run into this problem earlier so that I can solve it.

+8
python flask forms flask-wtforms wtforms
source share
1 answer

This is a bit confusing because you are processing index.html for both index () and register (), and both are registering the same route ( @application.route('/index') ). When you submit your form to /index , only one of them is only ever called. You can either

  • put all your logic in one index function and see what form (if any) is valid.
  • share your logic and submit the appropriate form

As a rule, you want to separate the logic, even if you want to show both the login and registration on the same page. Therefore, I will try to show you in the right direction :-)

For example, first separate your registration and registration submissions, which will now only check the logic of the form that applies to them:

 class Login(Form): login_user = TextField('Username', [validators.Required()]) login_pass = PasswordField('Password', [validators.Required()]) class Register(Form): username = TextField('Username', [validators.Length(min=1, max = 12)]) password = PasswordField('Password', [ validators.Required(), validators.EqualTo('confirm_password', message='Passwords do not match') ]) confirm_password = PasswordField('Confirm Password') email = TextField('Email', [validators.Length(min=6, max=35)]) @application.route('/login', methods=['POST']) def index(): l_form = Login(request.form, prefix="login-form") if l_form.validate(): check_login = cursor.execute("SELECT * FROM users WHERE username = '%s' AND pwd = '%s'" % (l_form.login_user.data, hashlib.sha1(l_form.login_pass.data).hexdigest())) if check_login == True: conn.commit() return redirect(url_for('me')) return render_template('index.html', lform=l_form, rform=Register()) @application.route('/register', methods=['POST']) def register(): r_form = Register(request.form, prefix="register-form") if r_form.validate(): check_reg = cursor.execute("SELECT * FROM users WHERE username = '%s' OR `e-mail` = '%s'" % (r_form.username.data, r_form.email.data)) if check_reg == False: cursor.execute("INSERT into users (username, pwd, `e-mail`) VALUES ('%s','%s','%s')" % (r_form.username.data, hashlib.sha1(r_form.password.data).hexdigest(), check_email(r_form.email.data))) conn.commit() return redirect(url_for('index')) return render_template('index.html', lform=Login(), rform=r_form) @application.route('/index') def index(): # If user is logged in, show useful information here, otherwise show login and register return render_template('index.html', lform=Login(), rform=Register()) 

Then create an index.html that shows both forms and sends them in the right direction.

 <form name="lform" method="post" action="{{ url_for('login') }}"> {{ lform.login_user }} {{ lform.login_pass }} <input type="submit" value="Login" /> </form> <form name="rform" method="post" action="{{ url_for('register') }}"> {{ rform.username }} {{ rform.email }} {{ rform.password }} {{ rform.confirm_password }} <input type="submit" value="Register" /> </form> 

The code has not been verified, so there may be errors, but I hope it sends you in the right direction. Note that we pass both lform and rform in all render calls ('index.html', ...).

Other simple ways to improve / refactor: use a function to validate an existing user (your SELECT ) and use Jinja2 or macros for individual forms in templates.

+13
source share

All Articles