Python Flask Multi-Step Registration Form With MySQL jQuery

Multi-Step Registration Form

You will see an example on Python Flask multi-step registration form with MySQL, jQuery. Sometimes you may need to capture lots of user details during registration process and as a result a user gets a long form on web page. So the best solution is to break the form into smaller logical section and present it into a multi step registration form. This type of multi-step registration form always improves usability on web page comparing to very long form.

You may also like to read Multi-step registration form using Codeigniter, MySQL and jQuery.

Prerequisite

Python 3.7.4/3.11.5, Flask 1.1.1/2.2.3, MySQL 8.0.17/8.1.0, Windows 10/11 64 bit

Project Directory

First step is to create a project root directory under which I will put all our required files for the project.

Let’s say I am going to create a project root directory python-flask-mysql-jquery-ajax-multi-step-registration.

I may not mention the project root directory in subsequent sections and I will assume that I am talking with respect to the project’s root directory.

MySQL Table

Create a table user under database roytuts in MySQL server with the following structure:

CREATE TABLE `user` (
	`id` INT NOT NULL AUTO_INCREMENT,
	`name` VARCHAR(100) NOT NULL,
	`password` VARCHAR(255) NULL,
	`email` VARCHAR(100) NULL,
	`phone` VARCHAR(20) NOT NULL,
	`gender` VARCHAR(6) NOT NULL,
	`dob` VARCHAR(10) NOT NULL,
	`address` VARCHAR(255) NOT NULL,
	PRIMARY KEY (`id`)
) COLLATE='utf8mb4_unicode_ci' ENGINE=InnoDB;

Configuring Flask

Create the below app.py script(py is the extension to indicate Python script) where I import the flask module. This file should be created under the project root directory. Notice how I create flask instance. I have configured a secret key, which is required for your application’s flash or session. In this application I will use flash to give users feedback.

from flask import Flask

app = Flask(__name__)
app.secret_key = "secret key"

Database Configuration

I create the below db_config.py Python script under project root directory to setup the MySQL database configurations for connecting to database.

I need to configure database connection with flask module and that’s why I have imported app module and setup the MySQL configuration with flask module.

from app import app
from flaskext.mysql import MySQL

mysql = MySQL()
 
# MySQL configurations
app.config['MYSQL_DATABASE_USER'] = 'root'
app.config['MYSQL_DATABASE_PASSWORD'] = 'root'
app.config['MYSQL_DATABASE_DB'] = 'roytuts'
app.config['MYSQL_DATABASE_HOST'] = 'localhost'
mysql.init_app(app)

Configuring URLs

Next I will create main.py script that will define all URIs or Action paths for saving user information into the database.

I first import required modules into the script. I then define the end-point / for displaying a view where user will see the multi step registration page.

Next I need to validate user input data and save those input data into database. So I define another end-point /register.

I use http method GET for displaying view and POST method for sending data to server side. By default http method is GET if you do not specify http method.

I use render_template function from flask to show the view.

import pymysql
from app import app
from db_config import mysql
from flask import flash, render_template, request, redirect, url_for
#from werkzeug import generate_password_hash, check_password_hash version 1.x
from werkzeug.security import generate_password_hash, check_password_hash # version 2.x
		
@app.route('/register', methods=['POST'])
def save_user_info():
	cursor = None
	try:
		name = request.form['name']
		dob = request.form['dob']
		gender = request.form['gender']
		password = request.form['password']
		phone = request.form['phone']
		email = request.form['email']
		address = request.form['address']
		
		# validate the received values
		if name and dob and gender and password and phone and email and address and request.method == 'POST':
		
			#do not save password as a plain text
			_hashed_password = generate_password_hash(password)
			
			# save user information
			sql = "INSERT INTO user(name, password, email, phone, gender, dob, address) VALUES(%s, %s, %s, %s, %s, %s, %s)"
			data = (name, _hashed_password, email, phone, gender, dob, address)
			conn = mysql.connect()
			cursor = conn.cursor()
			cursor.execute(sql, data)
			conn.commit()
			
			flash('You registered successfully!')
			
			return redirect(url_for('.home'))
		else:			
			return 'Error while saving user information'
	except Exception as e:
		print(e)
	finally:
		cursor.close() 
		conn.close()
		
@app.route('/')
def home():
	return render_template('multi-step-registration.html')
		
if __name__ == "__main__":
    app.run()

Template – View File

Now create multi-step-registration.html file and put it under templates directory.

Notice how I am using flask EL expression to use variable to show data into HTML file.

I will use jQuery to validate the user input before I save into the MySQL table. I will also validate whether user has input all the required input fields before going to the next step.

I also check for any success or error message and display them. I display messages from flash scope and for this we need secret key and that’s why I have configured Secret Key in app.py script.

<html>
    <head>
        <title>Multi Step Registration</title>
        <style>
            body {
                font-family:tahoma;
                font-size:12px;
            }

            #signup-step {
                margin:auto;
                padding:0;
                width:53%
            }

            #signup-step li {
                list-style:none; 
                float:left;
                padding:5px 10px;
                border-top:#004C9C 1px solid;
                border-left:#004C9C 1px solid;
                border-right:#004C9C 1px solid;
                border-radius:5px 5px 0 0;
            }

            .active {
                color:#FFF;
            }

            #signup-step li.active {
                background-color:#004C9C;
            }

            #signup-form {
                clear:both;
                border:1px #004C9C solid;
                padding:20px;
                width:50%;
                margin:auto;
            }

            .demoInputBox {
                padding: 10px;
                border: #CDCDCD 1px solid;
                border-radius: 4px;
                background-color: #FFF;
                width: 50%;
            }

            .signup-error {
                color:#FF0000; 
                padding-left:15px;
            }

            .message {
                color: #00FF00;
                font-weight: bold;
                width: 100%;
                padding: 10;
            }

            .btnAction {
                padding: 5px 10px;
                background-color: #F00;
                border: 0;
                color: #FFF;
                cursor: pointer;
                margin-top:15px;
            }

            label {
                line-height:35px;
            }

        </style>

        <!--<script src="http://code.jquery.com/jquery-1.10.2.js"></script>-->
		<script src="https://code.jquery.com/jquery-3.7.1.min.js" integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>

        <script>
            function validate() {
                var output = true;
                $(".signup-error").html('');

                if ($("#personal-field").css('display') != 'none') {
                    if (!($("#name").val())) {
                        output = false;
                        $("#name-error").html("Name required!");
                    }

                    if (!($("#dob").val())) {
                        output = false;
                        $("#dob-error").html("Date of Birth required!");
                    }
                }

                if ($("#password-field").css('display') != 'none') {
                    if (!($("#user-password").val())) {
                        output = false;
                        $("#password-error").html("Password required!");
                    }

                    if (!($("#confirm-password").val())) {
                        output = false;
                        $("#confirm-password-error").html("Confirm password required!");
                    }

                    if ($("#user-password").val() != $("#confirm-password").val()) {
                        output = false;
                        $("#confirm-password-error").html("Password not matched!");
                    }
                }

                if ($("#contact-field").css('display') != 'none') {
                    if (!($("#phone").val())) {
                        output = false;
                        $("#phone-error").html("Phone required!");
                    }

                    if (!($("#email").val())) {
                        output = false;
                        $("#email-error").html("Email required!");
                    }

                    if (!$("#email").val().match(/^([\w-\.]+@([\w-]+\.)+[\w-]{2,4})?$/)) {
                        $("#email-error").html("Invalid Email!");
                        output = false;
                    }

                    if (!($("#address").val())) {
                        output = false;
                        $("#address-error").html("Address required!");
                    }
                }

                return output;
            }

            $(document).ready(function () {
                $("#next").click(function () {
                    var output = validate();
                    if (output === true) {
                        var current = $(".active");
                        var next = $(".active").next("li");
                        if (next.length > 0) {
                            $("#" + current.attr("id") + "-field").hide();
                            $("#" + next.attr("id") + "-field").show();
                            $("#back").show();
                            $("#finish").hide();
                            $(".active").removeClass("active");
                            next.addClass("active");
                            if ($(".active").attr("id") == $("li").last().attr("id")) {
                                $("#next").hide();
                                $("#finish").show();
                            }
                        }
                    }
                });


                $("#back").click(function () {
                    var current = $(".active");
                    var prev = $(".active").prev("li");
                    if (prev.length > 0) {
                        $("#" + current.attr("id") + "-field").hide();
                        $("#" + prev.attr("id") + "-field").show();
                        $("#next").show();
                        $("#finish").hide();
                        $(".active").removeClass("active");
                        prev.addClass("active");
                        if ($(".active").attr("id") == $("li").first().attr("id")) {
                            $("#back").hide();
                        }
                    }
                });

                $("input#finish").click(function (e) {
                    var output = validate();
                    var current = $(".active");

                    if (output === true) {
                        return true;
                    } else {
                        //prevent refresh
                        e.preventDefault();
                        $("#" + current.attr("id") + "-field").show();
                        $("#back").show();
                        $("#finish").show();
                    }
                });
            });
        </script>

    </head>
    <body>
        <ul id="signup-step">
            <li id="personal" class="active">Personal Detail</li>
            <li id="password">Password</li>
            <li id="contact">Contact</li>
        </ul>

        <div>
			{% with messages = get_flashed_messages() %}
			  {% if messages %}
				<ul>
				{% for message in messages %}
				  <li>{{ message }}</li>
				{% endfor %}
				</ul>
			  {% endif %}
			{% endwith %}
		</div>
		
		<div>
			<form name="frmRegistration" id="signup-form" method="post" action="/register">
				<div id="personal-field">
					<label>Name</label><span id="name-error" class="signup-error"></span>
					<div><input type="text" name="name" id="name" class="demoInputBox"/></div>
					<label>Date of Birth</label><span id="dob-error" class="signup-error"></span>
					<div><input type="text" name="dob" id="dob" class="demoInputBox"/></div>
					<label>Gender</label>
					<div>
						<select name="gender" id="gender" class="demoInputBox">
							<option value="male">Male</option>
							<option value="female">Female</option>                                                                         
						</select>
					</div>
				</div>

				<div id="password-field" style="display:none;">
					<label>Enter Password</label><span id="password-error" class="signup-error"></span>
					<div><input type="password" name="password" id="user-password" class="demoInputBox" /></div>
					<label>Re-enter Password</label><span id="confirm-password-error" class="signup-error"></span>
					<div><input type="password" name="confirm-password" id="confirm-password" class="demoInputBox" /></div>
				</div>

				<div id="contact-field" style="display:none;">
					<label>Phone</label><span id="phone-error" class="signup-error"></span>
					<div><input type="text" name="phone" id="phone" class="demoInputBox" /></div>
					<label>Email</label><span id="email-error" class="signup-error"></span>
					<div><input type="text" name="email" id="email" class="demoInputBox" /></div>
					<label>Address</label><span id="address-error" class="signup-error"></span>
					<div><textarea name="address" id="address" class="demoInputBox" rows="5" cols="50"></textarea></div>
				</div>

				<div>
					<input class="btnAction" type="button" name="back" id="back" value="Back" style="display:none;">
					<input class="btnAction" type="button" name="next" id="next" value="Next" >
					<input class="btnAction" type="submit" name="finish" id="finish" value="Finish" style="display:none;">
				</div>
			</form>
		</div>
    </body>
</html>

Testing the Multi Step Registration Form Application

Now run the application by executing main.py using command python main.py and hit the URL http://localhost:5000/ in the browser. You will see below output on the browser.

multi step form using python flask mysql jquery

If you try to submit the form without filling data then you will see validation errors.

You will also see that you cannot proceed to the next step until you fill all required fields in the current step.

Password Tab

multi step form using python flask mysql jquery

Contact Tab

multi step form using python flask mysql jquery

Once you fill the form with all input fields and you will find one row has been inserted into the database table.

Source Code

Download

Leave a Reply

Your email address will not be published. Required fields are marked *