DEV Community

Cover image for Build your first website with flask!
chrisMurimi
chrisMurimi

Posted on

Build your first website with flask!

In this tutorial, we'll be creating a complete login and registration system with Python Flask and MySQL.

Python is currently taking the web development scene by storm, growing consistently every year. It's easy to get started with Python and doesn't require as many dependencies that you need to download separately.

To get started with the project will set up the required packages for our project.

mkdir flaskproject
Enter fullscreen mode Exit fullscreen mode

use the above command to create your project directory that will hold your project files.
Then navigate to the directory and create your python project file.
navigating to the directory we have created for the project

cd flaskproject
Enter fullscreen mode Exit fullscreen mode

creating our python project

touch flaskweb.py
Enter fullscreen mode Exit fullscreen mode

we will also create a folder named templates that will hold our html files and another file named static that will hold the css files.

we will create our html files here

mkdir templates
Enter fullscreen mode Exit fullscreen mode

we will create our css files here

mkdir static
Enter fullscreen mode Exit fullscreen mode

We will then install a virtual environment in our flaskproject folder. Python virtual environments help decouple and isolate versions of Python and associated pip packages. This allows end-users to install and manage their own set of packages that are independent of those provided by the system. Run the following command on you command prompt.

pip install virtualenv
Enter fullscreen mode Exit fullscreen mode

we will then create a virtual environment for our project.

virtualenv dev
Enter fullscreen mode Exit fullscreen mode

we will then start the virtual environment.

source dev/Scripts/activate
Enter fullscreen mode Exit fullscreen mode

To be able to use flask we need to install it to our project. Using pip on your command prompt install flask.

pip install flask
Enter fullscreen mode Exit fullscreen mode

we are now set to start the project. Open the project in your favorite IDE. For my case I love vscode. Add to open my project on my command prompt I can run the following command.

code flaskweb.py
Enter fullscreen mode Exit fullscreen mode

We then build the very basic flask app and run to test if everything is working perfect.

from flask import  Flask

app = Flask(__name__)

@app.route("/")
def regiter():

    return <h1>my first flask project</h1>


if __name__ == "__main__":
    app.run(debug=True)

Enter fullscreen mode Exit fullscreen mode

If every thing is working perfectly, create your html and css files. Go to the template folder and create and create 'login.html', 'layout.html', and 'home.html' files. Then open the static folder and create a file named 'style.css'. Note you can open the folder in the vscode and add the files from there.
Your folder should look like this

We will then create functions with routes, and render our html files.

from flask import Flask, render_template, request, url_for, session

app = Flask(__name__)

@app.route("/")
def home():
    #our code will co here
    return render_template('home.html')

@app.route("/login")
def login():
    #our code will co here
    return render_template('login.html')

@app.route("/logout")
def logout():
    #our code will co here
    return redirect(url_for('login'))

@app.route("/register")
def register():
    #our code will co here
    return redirect('register.html')


if __name__ == "__main__":
    app.run(debug=True)

Enter fullscreen mode Exit fullscreen mode

We are now going d design our web page using html and css. We will first create our layout page that will hold the similar content for all our html files to reduce redundancy.

<!DOCTYPE html>
<html>
    <head>

         {% block title %}
        <!-- we are using jinja templates to create a block where code from other html files will be passed-->
        {% endblock title %}

        <link rel="stylesheet" href="{{url_for('static', filename='login.css')}}">
    </head>


    <body>
    {% block body%}


    {%endblock body%}
    </body>
</html>
Enter fullscreen mode Exit fullscreen mode

you can learn more about jinja templates here

We will then create login and register forms in our login.html file.

{% extends 'layout.html' %}
{% block title%}
<title>
   {%if title%} 
        {{title}}
    {% else%}
        login
    {% endif %}
    </title>




{%endblock title%}

{% block body%}
<div class="login-wrap">
    <div class="login-html">
        <input id="tab-1" type="radio" name="tab" class="sign-in" checked><label for="tab-1" class="tab">Sign In</label>
        <input id="tab-2" type="radio" name="tab" class="sign-up"><label for="tab-2" class="tab">Sign Up</label>
        <div class="login-form">
            <div class="sign-in-htm">


                <form action="{{ url_for('login') }}" method="post" >
                    <div class="group">
                        <label for="user" class="label">Username</label>
                        <input id="user" type="text" class="input" name="Username">
                    </div>
                    <div class="group">
                        <label for="pass" class="label">Password</label>
                        <input id="pass" type="password" class="input" data-type="password" name="password">
                    </div>
                    <div class="group">
                        <input id="check" type="checkbox" class="check" checked>
                        <label for="check"><span class="icon"></span> Keep me Signed in</label>
                    </div>
                    <div class="msg">{{ msg }}</div>
                    <div class="group">
                        <input type="submit" class="button" value="Sign In">
                    </div>
                </form>


                <div class="hr"></div>
                <div class="foot-lnk">
                    <a href="#forgot">Forgot Password?</a>
                </div>
            </div>
            <div class="sign-up-htm">


            <form action="{{ url_for('register') }}" method="post">
                    <div class="group">
                        <label for="user" class="label" name="username">Username</label>
                        <input id="user" type="text" class="input">
                    </div>
                    <div class="group">
                        <label for="pass" class="label" name="password">Password</label>
                        <input id="pass" type="password" class="input" data-type="password">
                    </div>
                    <div class="group">
                        <label for="pass" class="label" name="retry_password">Repeat Password</label>
                        <input id="pass" type="password" class="input" data-type="password">
                    </div>
                    <div class="group">
                        <label for="pass" class="label" name="email">Email Address</label>
                        <input id="pass" type="text" class="input">
                    </div>
                    <div class="msg">{{ msg }}</div>
                    <div class="group">
                        <input type="submit" class="button" value="Sign Up">
                    </div>
            </form>


                <div class="hr"></div>
                <div class="foot-lnk">
                    <label for="tab-1">Already Member?</a>
                </div>
            </div>
        </div>
    </div>



</div>

{%endblock body%}
Enter fullscreen mode Exit fullscreen mode

We will then create our home page.

{% extends 'layout.html' %}
{% block title%}
<title>
   {%if title%} 
        {{title}}
    {% else%}
        home
    {% endif %}
    </title>
{%endblock title%}

{% block body%}

<h2>Home Page</h2>
<p>Welcome back, {{ username }}!</p>

{%endblock body%}
Enter fullscreen mode Exit fullscreen mode

The we are going to add content in our style.css file in our static folder.

body{
    margin:0;
    background:url(../images/loginbackground.jpg) no-repeat center;
    font:600 16px/18px 'Open Sans',sans-serif;
    padding: 0;
}
*,:after,:before{box-sizing:border-box}
.clearfix:after,.clearfix:before{content:'';display:table}
.clearfix:after{clear:both;display:block}
a{color:inherit;text-decoration:none}

.login-wrap{
    width:100%;
    margin:auto;
    max-width:525px;
    min-height:670px;
    position:relative;
    background:url(https://raw.githubusercontent.com/khadkamhn/day-01-login-form/master/img/bg.jpg) no-repeat center;
    box-shadow:0 12px 15px 0 rgba(0,0,0,.24),0 17px 50px 0 rgba(0,0,0,.19);
}
.login-html{
    width:100%;
    height:100%;
    position:absolute;
    padding:90px 70px 50px 70px;
    background:rgba(40,57,101,.9);
}
.login-html .sign-in-htm,
.login-html .sign-up-htm{
    top:0;
    left:0;
    right:0;
    bottom:0;
    position:absolute;
    transform:rotateY(180deg);
    backface-visibility:hidden;
    transition:all .4s linear;
}
.login-html .sign-in,
.login-html .sign-up,
.login-form .group .check{
    display:none;
}
.login-html .tab,
.login-form .group .label,
.login-form .group .button{
    text-transform:uppercase;
}
.login-html .tab{
    font-size:22px;
    margin-right:15px;
    padding-bottom:5px;
    margin:0 15px 10px 0;
    display:inline-block;
    border-bottom:2px solid transparent;
}
.login-html .sign-in:checked + .tab,
.login-html .sign-up:checked + .tab{
    color:#fff;
    border-color:#1161ee;
}
.login-form{
    min-height:345px;
    position:relative;
    perspective:1000px;
    transform-style:preserve-3d;
}
.login-form .group{
    margin-bottom:15px;
}
.login-form .group .label,
.login-form .group .input,
.login-form .group .button{
    width:100%;
    color:#fff;
    display:block;
}
.login-form .group .input,
.login-form .group .button{
    border:none;
    padding:15px 20px;
    border-radius:25px;
    background:rgba(255,255,255,.1);
}
.login-form .group input[data-type="password"]{
    text-decoration:circle;
    -webkit-text-security:circle;
}
.login-form .group .label{
    color:#aaa;
    font-size:12px;
}
.login-form .group .button{
    background:#1161ee;
}
.login-form .group label .icon{
    width:15px;
    height:15px;
    border-radius:2px;
    position:relative;
    display:inline-block;
    background:rgba(255,255,255,.1);
}
.login-form .group label .icon:before,
.login-form .group label .icon:after{
    content:'';
    width:10px;
    height:2px;
    background:#fff;
    position:absolute;
    transition:all .2s ease-in-out 0s;
}
.login-form .group label .icon:before{
    left:3px;
    width:5px;
    bottom:6px;
    transform:scale(0) rotate(0);
}
.login-form .group label .icon:after{
    top:6px;
    right:0;
    transform:scale(0) rotate(0);
}
.login-form .group .check:checked + label{
    color:#fff;
}
.login-form .group .check:checked + label .icon{
    background:#1161ee;
}
.login-form .group .check:checked + label .icon:before{
    transform:scale(1) rotate(45deg);
}
.login-form .group .check:checked + label .icon:after{
    transform:scale(1) rotate(-45deg);
}
.login-html .sign-in:checked + .tab + .sign-up + .tab + .login-form .sign-in-htm{
    transform:rotate(0);
}
.login-html .sign-up:checked + .tab + .login-form .sign-up-htm{
    transform:rotate(0);
}

.hr{
    height:2px;
    margin:60px 0 50px 0;
    background:rgba(255,255,255,.2);
}
.foot-lnk{
    text-align:center;
}
Enter fullscreen mode Exit fullscreen mode

What remains now is getting data from our html forms. But before we do that we have to connect our application with a database. In this case we are using mysql database.
You can download and install mysql database for your operating system here.
When your mySQL is set, navigate to the browser create a new database with your favorite name.
Then use the following sql code to create a table in your database with the given values

CREATE TABLE IF NOT EXISTS `users` (
    `id` int(11) NOT NULL AUTO_INCREMENT,
    `username` varchar(50) NOT NULL,
    `password` varchar(255) NOT NULL,
    `email` varchar(100) NOT NULL,
    PRIMARY KEY (`id`)
) ```




We will then link the database with our project. To facilatate this we have to install pymysql module that will help us in the connection. Open your command prompt and use pip to install the module.


```cmd
pip install pymysql
Enter fullscreen mode Exit fullscreen mode

we will then move to our flaskweb.py file and import the module.

from flask import Flask, render_template, request, url_for, session
import pymysql
Enter fullscreen mode Exit fullscreen mode

Using the module we will then create a connection with our database.

from flask import Flask, render_template, request, url_for, session
import pymysql

pp = Flask(__name__)


# database connection details 
# Intializing MySQL
connection = pymysql.connect(host='localhost', password='', user='root', database='luxproject')

Enter fullscreen mode Exit fullscreen mode

We will then retrive data from our html forms using post method we used to send the data to our route.

@app.route("/register", methods=['POST', 'GET'])
def regiter():
    if request.method == "POST":
        username = request.form['username']
        phone = request.form['phone']
        password = request.form['password']
Enter fullscreen mode Exit fullscreen mode

We will then check the data input by the user, validate if it meet our standard and send it to our data base.

@app.route('/register' , methods=['GET', 'POST'])
def register():
    msg=''
    # Check if "username", "password" and "email" POST requests exist (user submitted form)
    if request.method == 'POST' and 'username' in request.form and 'password' in request.form and 'email' in request.form:
        # Create variables for easy access
        username = request.form['username']
        password = request.form['password']
        email = request.form['email']
        # Show registration form with message (if any)
        cursor = connection.cursor()
        cursor.execute('SELECT * FROM users WHERE username = {}'.format(username,))
        account = cursor.fetchone()
        # If account exists show error and validation checks
        if account:
            msg = 'Account already exists!'
        elif not re.match(r'[^@]+@[^@]+\.[^@]+', email):
            msg = 'Invalid email address!'
        elif not re.match(r'[A-Za-z0-9]+', username):
            msg = 'Username must contain only characters and numbers!'
        elif not username or not password or not email:
            msg = 'Please fill out the form!'
        else:
            # Account doesnt exists and the form data is valid, now insert new account into accounts table
            cursor.execute('INSERT INTO users VALUES (NULL, %s, %s, %s)', (username, password, email,))
            connection.commit()
            msg = 'You have successfully registered!'
    elif request.method == 'POST':
        # Form is empty... (no POST data)
        msg = 'Please fill out the form!'



    return render_template('login.html', msg=msg)
Enter fullscreen mode Exit fullscreen mode

We will also create our login session. Here we will get user input and compare with the data in our database, if user exist we will let him in.

@app.route('/login', methods=['GET', 'POST'])
def login():
    msg=''
     # Check if "username" and "password" POST requests exist (user submitted form)
    if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
        # Create variables for easy access
        username = request.form['username']
        password = request.form['password']
         # Check if account exists using MySQL
        cursor = connection.cursor()
        cursor.execute('SELECT * FROM users WHERE username = %s AND password = %s', (username, password,))

        # Fetch one record and return result
        account = cursor.fetchone()

     # If account exists in accounts table in out database
        if account:
            # Create session data, we can access this data in other routes
            session['loggedin'] = True
            session['id'] = account['id']
            session['username'] = account['username']
            # Redirect to home pag(
            return render_template('home.html')
        else:
            # Account doesnt exist or username/password incorrect
            msg = 'Incorrect username/password!'

    return render_template('login.html', msg=msg)
Enter fullscreen mode Exit fullscreen mode

We will also create the home and the logout functions.
Home function

def home():
    # Check if user is loggedin
    if 'loggedin' in session:
        # User is loggedin show them the home page
        return render_template('home.html', username=session['username'])
    # User is not loggedin redirect to login page
    return redirect(url_for('login'))
Enter fullscreen mode Exit fullscreen mode

logout function

@app.route('/pythonlogin/logout')
def logout():
    # Remove session data, this will log the user out
   session.pop('loggedin', None)
   session.pop('id', None)
   session.pop('username', None)
   # Redirect to login page
   return redirect(url_for('login'))
Enter fullscreen mode Exit fullscreen mode

Now our flaskweb.py file should look as follows.

import re
from flask import Flask, render_template, request, url_for, session
import pymysql
from werkzeug.utils import redirect


app = Flask(__name__)


# database connection details 
# Intializing MySQL
connection = pymysql.connect(host='localhost', password='', user='root', database='luxproject')


@app.route('/')
@app.route('/home')
def home():
    # Check if user is loggedin
    if 'loggedin' in session:
        # User is loggedin show them the home page
        return render_template('home.html', username=session['username'])
    # User is not loggedin redirect to login page
    return redirect(url_for('login'))


@app.route('/login', methods=['GET', 'POST'])
def login():
    msg=''
     # Check if "username" and "password" POST requests exist (user submitted form)
    if request.method == 'POST' and 'username' in request.form and 'password' in request.form:
        # Create variables for easy access
        username = request.form['username']
        password = request.form['password']
         # Check if account exists using MySQL
        cursor = connection.cursor()
        cursor.execute('SELECT * FROM users WHERE username = %s AND password = %s', (username, password,))

        # Fetch one record and return result
        account = cursor.fetchone()

     # If account exists in accounts table in out database
        if account:
            # Create session data, we can access this data in other routes
            session['loggedin'] = True
            session['id'] = account['id']
            session['username'] = account['username']
            # Redirect to home pag(
            return render_template('home.html')
        else:
            # Account doesnt exist or username/password incorrect
            msg = 'Incorrect username/password!'

    return render_template('login.html', msg=msg)



@app.route('/pythonlogin/logout')
def logout():
    # Remove session data, this will log the user out
   session.pop('loggedin', None)
   session.pop('id', None)
   session.pop('username', None)
   # Redirect to login page
   return redirect(url_for('login'))


@app.route('/register' , methods=['GET', 'POST'])
def register():
    msg=''
    # Check if "username", "password" and "email" POST requests exist (user submitted form)
    if request.method == 'POST' and 'username' in request.form and 'password' in request.form and 'email' in request.form:
        # Create variables for easy access
        username = request.form['username']
        password = request.form['password']
        email = request.form['email']
        # Show registration form with message (if any)
        cursor = connection.cursor()
        cursor.execute('SELECT * FROM users WHERE username = {}'.format(username,))
        account = cursor.fetchone()
        # If account exists show error and validation checks
        if account:
            msg = 'Account already exists!'
        elif not re.match(r'[^@]+@[^@]+\.[^@]+', email):
            msg = 'Invalid email address!'
        elif not re.match(r'[A-Za-z0-9]+', username):
            msg = 'Username must contain only characters and numbers!'
        elif not username or not password or not email:
            msg = 'Please fill out the form!'
        else:
            # Account doesnt exists and the form data is valid, now insert new account into accounts table
            cursor.execute('INSERT INTO users VALUES (NULL, %s, %s, %s)', (username, password, email,))
            connection.commit()
            msg = 'You have successfully registered!'
    elif request.method == 'POST':
        # Form is empty... (no POST data)
        msg = 'Please fill out the form!'



    return render_template('login.html', msg=msg)


if __name__ == ('__main__'):
    app.run(debug=True)
Enter fullscreen mode Exit fullscreen mode

Now you have developed you first flask website. Do you fill excited! You can clone the project here. Feel free to drop your in put.

Discussion (0)