Build your first website with flask!
Tags: flask, python, webdev, tutorial
Published: 2021-08-27 19:48:48

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.

```cmd 
mkdir flaskproject
```
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**
```cmd 
cd flaskproject
```

**creating our python project**
```cmd 
touch flaskweb.py
```
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**
```cmd 
mkdir templates
```

**we will create our css files here**
```cmd 
mkdir static
```

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.
```cmd 
pip install virtualenv
```
we will then create a virtual environment for our project.
```cmd 
virtualenv dev
```
we will then start the virtual environment.
```cmd 
source dev/Scripts/activate
```

To be able to use flask we need to install it to our project. Using pip on your command prompt install flask.
```cmd 
pip install flask
```
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.

```cmd 
code flaskweb.py
```
We then build the very basic flask app and run to test if everything is working perfect.

```python
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)

```

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](/C:/Users/chris murimi/Pictures/Screenshots/Screenshot (311).png)

We will then create functions with routes, and render our html files.
```python
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)

```
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. 
```html
<!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>
```
![you can learn more about jinja templates here](https://flask.palletsprojects.com/en/2.0.x/tutorial/templates/ )

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

```html
{% 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%}
```

We will then create our home page.
```html
{% 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%}
```

The we are going to add content in our style.css file in our static folder.
```css
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;
}
```

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](https://www.mysql.com/downloads/).
When your mySQL is set, ![navigate to the browser](http://localhost/phpmyadmin/sql.php?) 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
```sql
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
```
we will then move to our flaskweb.py file and import the module.
```python
from flask import Flask, render_template, request, url_for, session
import pymysql
```
Using the module we will then create a connection with our database.
```python
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')

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

```python
@app.route("/register", methods=['POST', 'GET'])
def regiter():
    if request.method == "POST":
        username = request.form['username']
        phone = request.form['phone']
        password = request.form['password']
```
We will then check the data input by the user, validate if it meet our standard and send it to our data base.
```python
@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)
```
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.

```python
@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)
```
We will also create the home and the logout functions.
**Home function**

``` python
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'))
```
**logout function**
``` python
@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'))
```

Now our flaskweb.py file should look as follows.

```python
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)
```
Now you have developed you first flask website. Do you fill excited! ![You can clone the project here](https://github.com/chrisMurimi/luxFinalProject). Feel free to drop your in put.