Python course Β· Module 5: Flask and Web Apps

Flask - web microframework

11 min read
In this lesson11

Welcome back! Darwin here, ready to show you Flask - the most popular web microframework in Python!

In the previous lesson you learned frontend basics (HTML, CSS, JavaScript). Now we'll combine that with Python using Flask!

Safari Analogy: Flask is like a mobile research center - lightweight, flexible, you can easily move it anywhere and quickly start observations! You don't need a huge laboratory (Django) to begin research.

What is Flask?

Flask is a microframework for web development written in Python by Armin Ronacher in 2010.

Microframework = a minimalist framework with basic features that you can extend with plugins.

Flask vs Django

FlaskDjango
Microframework - minimalistFull-stack framework - all-in-one
Flexible, modularOpinionated, conventions
Great for small/medium projectsGreat for large projects
You choose components yourselfEverything out-of-the-box
~10 lines for Hello World~50 lines for Hello World
Great for learning!More complex

Analogy: Flask is a research tent (quick setup), Django is a full laboratory (long configuration, but all tools included).

Why use Flask?

Simple - minimal learning curve Flexible - you choose the components Lightweight - small app, fast start Pythonic - clean, readable code Great documentation - easy to learn Large community - plenty of plugins

Flask use cases:

  • Prototypes and MVPs
  • Dashboards and admin panels
  • APIs for mobile apps
  • Data visualizations
  • Educational projects

Installing Flask

Flask is installed via pip like any Python package.

Step 1: Create a virtual environment

Always use a virtual environment for Python projects!

1# Create project folder
2mkdir safari_web
3cd safari_web
4
5# Create virtual environment
6python -m venv venv
7
8# Activate environment
9# Windows:
10venv\\Scripts\\activate
11# Mac/Linux:
12source venv/bin/activate

Analogy: A virtual environment is like a separate enclosure for your project - libraries from one project won't conflict with others!

Step 2: Install Flask

1# Install Flask
2pip install Flask
3
4# Check version
5flask --version
6# Output: Python 3.11.0
7#         Flask 3.0.0
8#         Werkzeug 3.0.0

Flask automatically installs:

  • Werkzeug - WSGI utility library (routing, debugging)
  • Jinja2 - template engine (dynamic HTML)
  • MarkupSafe - safe HTML rendering
  • ItsDangerous - secure data signing
  • Click - CLI framework

Step 3: Create requirements.txt

1# Save dependencies
2pip freeze > requirements.txt
3
4# Contents of requirements.txt:
5Flask==3.0.0
6Werkzeug==3.0.0
7Jinja2==3.1.2
8...

Why? Other developers can install the same versions:

1pip install -r requirements.txt

First Flask application - Hello World

Time for your first Flask program! We'll create a page displaying "Hello Safari!"

Step 1: Create app.py

1# app.py
2from flask import Flask
3
4# Create Flask application instance
5app = Flask(__name__)
6
7# Define a route (URL address)
8@app.route('/')
9def hello():
10    return "Hello Safari!"
11
12# Run the development server
13if __name__ == '__main__':
14    app.run(debug=True)

What's happening?

  1. Flask(__name__) - creates an application instance

    • __name__ is the module name (Flask uses this to locate resources)
  2. @app.route('/') - decorator defining a route (URL path)

    • / = home page
    • When a user visits http://localhost:5000/, the hello() function executes
  3. def hello() - view function

    • Returns content that will be displayed to the user
  4. app.run(debug=True) - starts the development server

    • debug=True enables debug mode (auto-reload, detailed errors)

Step 2: Run the application

1python app.py

Output:

1 * Serving Flask app 'app'
2 * Debug mode: on
3WARNING: This is a development server. Do not use it in a production deployment.
4 * Running on http://127.0.0.1:5000
5Press CTRL+C to quit
6 * Restarting with stat
7 * Debugger is active!

Step 3: Open in browser

Go to: http://localhost:5000/

You'll see: Hello Safari!

Congratulations! You just created your first Flask application!

Anatomy of a Flask application

Let's analyze in more detail how Flask works.

1. Application instance

1from flask import Flask
2
3app = Flask(__name__)

Flask(__name__) creates an application object:

  • __name__ = module name (e.g. '__main__' or 'app')
  • Flask uses this to locate templates, static files

2. Routes (URL paths)

Route = mapping URL β†’ function

1@app.route('/species')
2def list_species():
3    return "List of all species"
4
5@app.route('/species/lion')
6def show_lion():
7    return "Lion details"

How it works?

  • User visits /species β†’ list_species() executes
  • User visits /species/lion β†’ show_lion() executes

Analogy: A route is like a safari trail - each trail leads to a different habitat (view function)!

3. View functions

View function = a function that returns an HTTP response

1@app.route('/')
2def home():
3    return "<h1>Safari Database</h1><p>Welcome to the system!</p>"

What can you return?

  • String - will be converted to HTML
  • HTML - rendered in the browser
  • JSON - for API (jsonify())
  • Template - dynamic HTML with Jinja2

4. Running the server

1if __name__ == '__main__':
2    app.run(debug=True)

Parameters of app.run():

  • debug=True - debug mode (auto-reload, debugger)
  • host='0.0.0.0' - accessible from other devices
  • port=5000 - port number (default 5000)

IMPORTANT: NEVER use debug=True in production!

Safari Database - first application

Let's create a simple Safari Database application with several routes!

app.py - full application

1# app.py
2from flask import Flask
3
4app = Flask(__name__)
5
6# Test data
7species = [
8    {"id": 1, "name": "Lion", "scientific_name": "Panthera leo", "population": 120},
9    {"id": 2, "name": "African Elephant", "scientific_name": "Loxodonta africana", "population": 450},
10    {"id": 3, "name": "Cheetah", "scientific_name": "Acinonyx jubatus", "population": 7100},
11]
12
13# Route 1: Home page
14@app.route('/')
15def home():
16    html = """
17    <!DOCTYPE html>
18    <html>
19    <head>
20        <title>Safari Database</title>
21        <style>
22            body {
23                font-family: Arial, sans-serif;
24                max-width: 800px;
25                margin: 50px auto;
26                padding: 20px;
27                background-color: #f4f1de;
28            }
29            h1 { color: #2c5f2d; }
30            nav { margin: 20px 0; }
31            nav a {
32                margin-right: 15px;
33                color: #2c5f2d;
34                text-decoration: none;
35                font-weight: bold;
36            }
37            nav a:hover { text-decoration: underline; }
38        </style>
39    </head>
40    <body>
41        <h1>Safari Database</h1>
42        <p>African species data management system</p>
43
44        <nav>
45            <a href="/">Home</a>
46            <a href="/species">Species list</a>
47            <a href="/about">About</a>
48        </nav>
49
50        <h2>Welcome to Safari Database!</h2>
51        <p>The database contains <strong>{} species</strong>.</p>
52        <p><a href="/species">See full species list β†’</a></p>
53    </body>
54    </html>
55    """.format(len(species))
56
57    return html
58
59# Route 2: Species list
60@app.route('/species')
61def list_species():
62    species_html = ""
63    for spec in species:
64        species_html += f"""
65        <div style="background: white; padding: 15px; margin: 10px 0; border-radius: 8px; border-left: 4px solid #2c5f2d;">
66            <h3>{spec['name']}</h3>
67            <p><strong>Scientific name:</strong> {spec['scientific_name']}</p>
68            <p><strong>Population:</strong> {spec['population']} individuals</p>
69            <a href="/species/{spec['id']}">See details β†’</a>
70        </div>
71        """
72
73    html = f"""
74    <!DOCTYPE html>
75    <html>
76    <head>
77        <title>Species list - Safari Database</title>
78        <style>
79            body {{
80                font-family: Arial, sans-serif;
81                max-width: 800px;
82                margin: 50px auto;
83                padding: 20px;
84                background-color: #f4f1de;
85            }}
86            h1 {{ color: #2c5f2d; }}
87            nav {{ margin: 20px 0; }}
88            nav a {{
89                margin-right: 15px;
90                color: #2c5f2d;
91                text-decoration: none;
92                font-weight: bold;
93            }}
94            nav a:hover {{ text-decoration: underline; }}
95        </style>
96    </head>
97    <body>
98        <h1>Species list</h1>
99
100        <nav>
101            <a href="/">Home</a>
102            <a href="/species">Species list</a>
103            <a href="/about">About</a>
104        </nav>
105
106        <p>Total: <strong>{len(species)} species</strong></p>
107
108        {species_html}
109
110        <p><a href="/">← Back to home page</a></p>
111    </body>
112    </html>
113    """
114
115    return html
116
117# Route 3: Species details (dynamic URL)
118@app.route('/species/<int:species_id>')
119def show_species(species_id):
120    # Find species by ID
121    spec = next((s for s in species if s['id'] == species_id), None)
122
123    if spec is None:
124        return "<h1>404 - Species not found</h1><a href='/species'>Back to list</a>", 404
125
126    html = f"""
127    <!DOCTYPE html>
128    <html>
129    <head>
130        <title>{spec['name']} - Safari Database</title>
131        <style>
132            body {{
133                font-family: Arial, sans-serif;
134                max-width: 800px;
135                margin: 50px auto;
136                padding: 20px;
137                background-color: #f4f1de;
138            }}
139            h1 {{ color: #2c5f2d; }}
140            .card {{
141                background: white;
142                padding: 30px;
143                border-radius: 12px;
144                border: 3px solid #2c5f2d;
145            }}
146        </style>
147    </head>
148    <body>
149        <h1>{spec['name']}</h1>
150
151        <div class="card">
152            <h2>{spec['name']}</h2>
153            <p><strong>Scientific name:</strong> <em>{spec['scientific_name']}</em></p>
154            <p><strong>Population:</strong> {spec['population']} individuals</p>
155            <p><strong>System ID:</strong> {spec['id']}</p>
156        </div>
157
158        <p style="margin-top: 20px;">
159            <a href="/species">← Back to species list</a> |
160            <a href="/">← Home page</a>
161        </p>
162    </body>
163    </html>
164    """
165
166    return html
167
168# Route 4: About the system
169@app.route('/about')
170def about():
171    html = """
172    <!DOCTYPE html>
173    <html>
174    <head>
175        <title>About - Safari Database</title>
176        <style>
177            body {
178                font-family: Arial, sans-serif;
179                max-width: 800px;
180                margin: 50px auto;
181                padding: 20px;
182                background-color: #f4f1de;
183            }
184            h1 { color: #2c5f2d; }
185        </style>
186    </head>
187    <body>
188        <h1>About Safari Database</h1>
189
190        <p><strong>Safari Database</strong> is an African species data management system.</p>
191
192        <h2>Technologies:</h2>
193        <ul>
194            <li>Flask 3.0 - web microframework</li>
195            <li>Python 3.11 - programming language</li>
196            <li>HTML/CSS - frontend</li>
197        </ul>
198
199        <h2>Features:</h2>
200        <ul>
201            <li>Browse species list</li>
202            <li>Details for each species</li>
203            <li>Population statistics</li>
204        </ul>
205
206        <p><a href="/">← Back to home page</a></p>
207    </body>
208    </html>
209    """
210
211    return html
212
213# Run development server
214if __name__ == '__main__':
215    print("Safari Database starting...")
216    print("Server available at: http://localhost:5000/")
217    app.run(debug=True)

Testing the application

1python app.py

Open in browser:

Also check errors:

Dynamic URLs - parameters

Flask allows dynamic URLs with parameters:

1# Basic parameter (string)
2@app.route('/user/<username>')
3def show_user(username):
4    return f"User: {username}"
5
6# Int type parameter
7@app.route('/species/<int:species_id>')
8def show_species(species_id):
9    return f"Species ID: {species_id}"
10
11# Float type parameter
12@app.route('/price/<float:price>')
13def show_price(price):
14    return f"Price: {price:.2f}"
15
16# Path parameter (can contain /)
17@app.route('/file/<path:filepath>')
18def show_file(filepath):
19    return f"File: {filepath}"

Converter types:

  • string - accepts text without slash (default)
  • int - accepts integers
  • float - accepts floating point numbers
  • path - like string, but accepts slashes
  • uuid - accepts UUID strings

URL examples:

1/user/darwin           β†’ username="darwin"
2/species/42            β†’ species_id=42
3/price/19.99           β†’ price=19.99
4/file/images/lion.jpg  β†’ filepath="images/lion.jpg"

HTTP Methods - GET and POST

Flask by default handles only GET requests. You can add other methods:

1from flask import request
2
3# GET only (default)
4@app.route('/species')
5def list_species():
6    return "Species list (GET)"
7
8# GET and POST
9@app.route('/species', methods=['GET', 'POST'])
10def species():
11    if request.method == 'POST':
12        # Handle form
13        name = request.form['name']
14        return f"Species added: {name}"
15    else:
16        # Display form
17        return """
18        <form method="POST">
19            <input type="text" name="name" placeholder="Species name">
20            <button type="submit">Add</button>
21        </form>
22        """
23
24# POST only
25@app.route('/api/species', methods=['POST'])
26def create_species():
27    return "Species created (POST only)"

HTTP Methods:

  • GET - retrieve data (default, safe)
  • POST - send data (forms, creation)
  • PUT - update data (full update)
  • PATCH - partial update
  • DELETE - delete data

Debugging and Auto-reload

Debug mode (debug=True) enables:

1. Auto-reload

The server automatically restarts after code changes!

1app.run(debug=True)

Test it:

  1. Run python app.py
  2. Change something in the code (e.g. text in a route)
  3. Save the file
  4. Flask automatically reloads the application!

2. Interactive debugger

When an error occurs, Flask shows an interactive debugger in the browser:

1@app.route('/error')
2def error():
3    result = 10 / 0  # Error: division by zero!
4    return "This won't be reached"

Visit /error β†’ you'll see a detailed traceback with the ability to inspect variables!

3. Detailed error messages

Flask shows exact error information instead of a generic "500 Internal Server Error".

IMPORTANT: NEVER use debug=True in production - it shows source code and allows code execution!

Flask CLI - alternative way to run

Instead of python app.py you can use Flask CLI:

1# Set environment variable
2export FLASK_APP=app.py
3export FLASK_DEBUG=1  # Enable debug mode
4
5# Run server
6flask run
7
8# Run on different port
9flask run --port 8000
10
11# Accessible from other devices
12flask run --host=0.0.0.0

Windows (PowerShell):

1$env:FLASK_APP = "app.py"
2$env:FLASK_DEBUG = "1"
3flask run

Flask project structure

A simple Flask project can look like this:

1safari_web/
2β”‚
3β”œβ”€β”€ venv/              # Virtual environment (don't commit to git!)
4β”‚
5β”œβ”€β”€ app.py             # Main application
6β”‚
7β”œβ”€β”€ requirements.txt   # Dependencies (pip freeze)
8β”‚
9β”œβ”€β”€ static/            # Static files (CSS, JS, images)
10β”‚   β”œβ”€β”€ css/
11β”‚   β”‚   └── style.css
12β”‚   β”œβ”€β”€ js/
13β”‚   β”‚   └── script.js
14β”‚   └── images/
15β”‚       └── logo.png
16β”‚
17β”œβ”€β”€ templates/         # HTML templates (Jinja2)
18β”‚   β”œβ”€β”€ base.html
19β”‚   β”œβ”€β”€ home.html
20β”‚   └── species.html
21β”‚
22└── .gitignore         # Ignore venv/, __pycache__/, etc.

In the next lesson we'll learn to use templates instead of hardcoded HTML strings!

Summary

In this lesson you learned:

  • What Flask is and why to use it
  • Installing Flask (pip install Flask)
  • First Flask program (Hello World)
  • Anatomy of a Flask application (app, routes, view functions)
  • Creating multiple routes
  • Dynamic URLs with parameters
  • Debug mode and auto-reload
  • Flask project structure

Final Safari Analogy: Flask is a mobile research center - lightweight, sets up quickly, you can start observations in minutes! You don't need a huge laboratory (Django) to begin Safari research!

Safari Database application code

You created a functioning web application with:

  • 4 routes (home, species list, species details, about)
  • Dynamic URLs (/species/<int:species_id>)
  • HTML + inline CSS
  • Test data (species list)

Next lesson: Darwin will show you routing and view functions - advanced techniques for creating routes, redirects, error handlers!

Spotted a mistake in this lesson?

Check yourself

Answer the questions from this lesson. Pick an answer to see right away whether it is correct.

  1. 1. How would you best describe Flask?

  2. 2. How do you install Flask using pip?

These are 2 of 3 questions for this lesson. Solve the rest in the game.

Hands-on tasks in the game

  • Vertical ordering

    Arrange the code of a minimal Flask application in the correct order:

  • Click in order

    How do you create a Flask application instance?

  • Code editor

    Write a Flask application with a '/' endpoint that returns 'Welcome to Safari!'

Useful articles