Python course Β· Module 5: Flask and Web Apps
Flask - web microframework
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
| Flask | Django |
|---|---|
| Microframework - minimalist | Full-stack framework - all-in-one |
| Flexible, modular | Opinionated, conventions |
| Great for small/medium projects | Great for large projects |
| You choose components yourself | Everything 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/activateAnalogy: 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.0Flask 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.txtFirst 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?
Flask(__name__)- creates an application instance__name__is the module name (Flask uses this to locate resources)
@app.route('/')- decorator defining a route (URL path)/= home page- When a user visits
http://localhost:5000/, thehello()function executes
def hello()- view function- Returns content that will be displayed to the user
app.run(debug=True)- starts the development serverdebug=Trueenables debug mode (auto-reload, detailed errors)
Step 2: Run the application
1python app.pyOutput:
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 devicesport=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.pyOpen in browser:
- http://localhost:5000/ - home page
- http://localhost:5000/species - species list
- http://localhost:5000/species/1 - lion details
- http://localhost:5000/species/2 - elephant details
- http://localhost:5000/about - about the system
Also check errors:
- http://localhost:5000/species/999 - species doesn't exist (404)
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 integersfloat- accepts floating point numberspath- like string, but accepts slashesuuid- 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:
- Run
python app.py - Change something in the code (e.g. text in a route)
- Save the file
- 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.0Windows (PowerShell):
1$env:FLASK_APP = "app.py"
2$env:FLASK_DEBUG = "1"
3flask runFlask 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. How would you best describe Flask?
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!'