Post

Creating a Website With Python and Flask

Flask is a lightweight Python framework used for developing web applications. In this module, I explore application structure, URL routing, and form handling, gaining hands-on experience with Flask and Python.

Creating a Website With Python and Flask

As someone who enjoys full-stack development and security-focused experimentation, I found this module particularly engaging. It will be my first attempt at creating a web application with Flask in Python.

This module of the course has helped educate me in knowing that consistent practice is what’s required to learn Python, and that the constant endeavour of building functional applications with Python is what bridges the knowledge gap between theoretical and experimental knowledge.

Flask is a Python framework used to develop full-stack web applications. It can help connect a database, use Python scripts, form handling, JavaScript, etc., whatever you can imagine as being a full-stack model of a website design. Flask is what can create that for you.

This session is all about hands-on practise in building websites with Flask, and for that purpose, I’ll instead write this post similar to a tutorial. This will help recollect the steps I took to make a website with Flask and all the functions available.


Web Frameworks in Python

There’s an open discussion regarding what framework is best to use to build a web application: Flask or Django. My own experience, from initial use, is that Flask is much easier to begin with. While both use templated layouts to build each page of the website, they differ in how they achieve the same goal.

Django is a more structured approach as it’s all about coding the logic first and then creating the visuals. Flask is more intuitive in the sense that it allows the user to start from wherever.

Templates are used to create page templates that are used throughout the website. You can build a navigation bar once and embed it into the template, which then populates the main content based on what the user wants to view.

Building a Flask Website

Now that we understand Flask, we can go ahead and start building our website.

Setting up a Virtual Environment

We’ll start by creating our virtual environment for Python, as this will help keep all packages we install and the work we do in a separate entity.

We start with a project folder, which can be named anything you prefer, and use the Command Line Interface to go into that project folder.

1
2
3
mkdir flask_project <- Making a folder on my Desktop
cd flask_project <- Moving into that folder
python -m venv venv <- Creating a Venv named Venv

Now that we have this all set up and ready, we need to activate it and begin our work.

Hint: My recommendation would be to use the VS Code terminal for the rest of the exercise, so close down the main Terminal and open again inside VS Code with the project folder loaded.

1
venv/Scripts/Activate.ps1.

Now install Flask:

1
pip install Flask

If you already had Flask installed on your local drive, you can just create a requirements.txt and use pip install -r requirements.txt to have everything installed instead.

Project Structure

Organisation and maintenance of folder structure is always crucial, as projects begin to expand, the folder structure can become obscure. This should be your folder structure as we begin:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
β”œβ”€β”€ app.py <- Main Python file
β”œβ”€β”€ venv <- venv folder
β”œβ”€β”€ requirements.txt
β”œβ”€β”€ static <- stores all 'static' files, i.e., media
β”‚   └── css
β”‚       └── main.css
└── templates <- stores all templates
    β”œβ”€β”€ home.html
    β”œβ”€β”€ about.html
    β”œβ”€β”€ layout.html
    β”œβ”€β”€ analyser.html
    └── partials
        β”œβ”€β”€ footer.html
        └── navbar.html

With the structure in place, the next step is to build the templates.

Creating the Base Template

We need the main template that all the pages would use. Effectively, this would be our index.html but created as layout.html. Once we have this, all other pages be an extension of this template.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

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

    {% if title %}
    <title>Example Site - {{ title }}</title>
    {% else %}
    <title>Example Site</title>
    {% endif %}
  </head>

  <body>
    <header>{% include 'partials/navbar.html' %}</header>
    <!-- This is where our header or navbar will insert itself -->
    <div class="body_container">
      <main>{% block content %} {% endblock %}</main>
      <!-- This is where other contents will 'inject' themselves in. -->
    </div>
    <footer>{% include 'partials/footer.html' %}</footer>
    <!-- This is where our footer will insert itself -->
  </body>
</html>

Anything inside {% %} or {{ }} is interpreted by Flask using the Jinja templating engine:

  • {{ variable }}: Outputs a value

  • {% … %}: Performs logic such as loops or conditionals

Creating Page Templates

Now let’s get the rest of the pages pre-built. For the most part, we can code it however we like. It’s best to think of it in the sense that we are coding the content side.

If we have any variables that we want have populated in rather than hard-coding, we can just use the syntax above.

Home Page

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{% extends 'layout.html' %}
<!-- Where we want to inherit CSS styling and specify where this information will go, we use 'extends' -->

{% block content %}
<div class="container">
  <h1>Welcome to {{ name }}</h1>
  <!-- For each page I will have the same header that populates the page name, i.e., about us, welcome to website, contact us... -->

  <p>
    This website was built using Flask to practise reusable templates and
    Python-powered web logic.
  </p>

  <p>Technologies covered so far:</p>

  <ol>
    {% for tech in techs %}

    <!-- This is using a for loop for items in a list called techs that I will specify later to demonstrate how Python and Flask work using the Jinja template to populate information -->

    <li>{{ tech }}</li>
    {% endfor %}
  </ol>
</div>
{% endblock %}

This template inherits the base layout and fills the content block.

About Page

1
2
3
4
5
6
7
8
9
{% extends 'layout.html' %} {% block content %}
<div class="container">
  <h1>About</h1>
  <p>
    This project is part of a structured Python learning challenge aimed at
    building practical skills through consistent practice.
  </p>
</div>
{% endblock %}

To keep my code modular, the header and footer were created as separate files. This way, if I want to do an update on either, I only need to modify one file.

1
2
<!-- footer.html -->
<p>&copy; 2026 Example Site Β· Built with Flask</p>

Now for the NavBar:

1
2
3
4
5
6
7
8
9
<!-- navbar.html -->
<nav>
  <ul>
    <li><a href="{{ url_for('home') }}">Home</a></li>
    <!-- The 'url_for' extracts the routing function from the app.py to take you to the relevant page -->
    <li><a href="{{ url_for('about') }}">About</a></li>
    <li><a href="{{ url_for('analyser') }}">Text Analyser</a></li>
  </ul>
</nav>

Creating code blocks for each page element gives you more control over how you can debug without needing to worry about repeating code.

Now that we have the templates all made, we need to code Python to use them all.

Creating the Flask Application

The app.py file ties everything together.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
from flask import Flask, render_template
import os

app = Flask(__name__)

@app.route('/')
def home():
    return render_template('home.html')

@app.route('/about')
def about():
    return render_template('about.html')

if __name__ == '__main__':
    port = int(os.environ.get("PORT", 5000))
    app.run(debug=True, host='0.0.0.0', port=port)

Running this file starts a local development server, allowing the site to be viewed in a browser.

Code Explained

I want to provide a thorough breakdown of the code so that I can understand it better.

1
app = Flask(__name__)

This calls on a function within Flask called (__name__), which houses all the Flask modules to make the rest of the code be interpreted as Flask Objects.

1
2
3
@app.route('/')
def home():
    return render_template('home.html')

This is using a decorator call function to bring back an existing function and store it into our object app.

We can then go ahead and create a new function inside it, which will append itself to the original function and behave as the old function with new abilities.

The new ability here happens to be the function that renders the template home.html and is activated when someone uses the URL /, which is the home URL.

Mental model:

[www.mywebsite.com] > [Launches function β€˜home’] > [Directs user to homepage].

1
2
3
4
5
6
if __name__ == '__main__':
# This is to make sure that the main file is the file that is using the application and not as an imported file.
    port = int(os.environ.get("PORT", 5000))
# This is to assign a port to use, and the usual port for development is port 5000.
    app.run(debug=True, host='0.0.0.0', port=port)
# This is what runs the complete function when we run the file and allows the website to provide debugging error messages in verbose mode. The host is set to '0.0.0.0' as it allows the application to be accessed via any local ip.

There’s a distinction to be made when it comes to comparing a development environment against a live deployment. A Flask application is usually started using only the app.run() function. This then runs everything inside the app.py folder using all the objects created.

A live deployment uses the app.py as an object or method in another file, typically a wsgi.py file. This file will be what uses everything inside app.py except with populating the ports and url.

Rendering Dynamic Values

Now that we have created our templates and logic, we want to start using dynamic values that we originally set in our HTML files. We need to assign values in our Python file as variables or functions to be called when used within the HTML document.

1
2
3
4
5
6
7
8
9
10
@app.route('/')
def home():
    techs = ['HTML', 'CSS', 'Python', 'Flask'] # {% for tech in techs %}
    name = 'Home' {{name}}
    return render_template(
        'home.html', # Use this template
        techs=techs, # techs = techs list
        name=name, # name = name variable
        title='Home' # title = "Home"
    )

Now, wherever we have used Jinja templating to insert Python variables and functions in our HTML code, these will appear.

Building a Text Analyser

This assignment in the course is what brought all my Python skills and newly learnt Flask and Jinja skills into use.

Objective

The project objective was to create a text analyser tool that takes a user input from a form box in HTML and using Python functions calculate the most frequent word, total characters, total words, lexical density of the most common word against the rest, and a summary of word counts for each word.

Here is all my code for it:

Python Logic

analyser.py:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def char_count(text):
    return len(text)

def word_count(text):
    return len(text.split())

def frequency_words(text):
    words = text.lower().split()
    freq = {}

    for word in words:
        freq[word] = freq.get(word, 0) + 1

    sorted_words = sorted(freq.items(), key=lambda x: x[1], reverse=True)
    return sorted_words[0]

def word_variety(freq_func, count_func, text):
    _, most_common_count = freq_func(text)
    total_words = count_func(text)
    return f"{(most_common_count / total_words) * 100:.2f}%"

HTML template

analyser.html:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{% extends 'layout.html' %} {% block content %}
<h1>{{ name }}</h1>

<form method="POST">
  <textarea
    name="text"
    rows="5"
    cols="50"
    placeholder="Enter text here"
  ></textarea>
  <button type="submit">Analyse</button>
</form>

{% if result %}
<ul>
  {% for key, value in result.items() %}
  <li><strong>{{ key }}:</strong> {{ value }}</li>
  {% endfor %}
</ul>
{% endif %} {% endblock %}

Flask Route

app.py append:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Copy code
@app.route('/analyser', methods=['GET', 'POST'])
def analyser():
    result = None
    name = "Text Analyser"

    if request.method == 'POST':
        text = request.form['text']
        result = {
            "Total Characters": char_count(text),
            "Total Words": word_count(text),
            "Most Frequent Word": frequency_words(text)[0],
            "Word Variety": word_variety(frequency_words, word_count, text)
        }

    return render_template('analyser.html', result=result, name=name)

I did rewrite most of this with ChatGPT for the purpose of writing this blog post. Therefore, some of the code has been changed. Other than that, this is the same logic I used to build my own.

I started with the analyser function first in a separate Python file and used the input() function to test and debug the code I made. Once that was ready, I removed the input() function from the analyser.py file and then created the HTML template and named the form user_input which was then taken to the app.py as an input function and imported in all my functions and gave them all parameters.

The initial input was considered as what was entered in the form box, when the button was clicked, it passed through the information to the parameters, used the functions to calculate and perform its magic. Have the parameters store the value, then display it on the template.

Summary

Overall, Flask has proven to be easier to work with than Django for smaller projects. It helped me with thinking more interms of building functions first and then importing them for use. It helped create a mental mindmap of how creating a full-stack design could look like, but I would still take the time to learn Django as it is renowned for it’s functionalities.

This has helped me build a solid foundation when it comes to working with Flask and creating full-stack web applications. Hopefully, after the end of the course i spend more time with Flask and Django to grasp more than just the basics.

This post is licensed under CC BY 4.0 by the author.