Python Flask Basics
Introduction
Flask is a lightweight and flexible web framework for Python. Created by Armin Ronacher, Flask is known as a micro-framework because it doesn't require particular tools or libraries, giving developers the freedom to choose components that best suit their projects. Despite its simplicity, Flask is powerful enough to build complex web applications.
In this tutorial, we'll explore the fundamental concepts of Flask and build a simple web application step by step. By the end, you'll understand how to set up routes, handle HTTP requests, render templates, and more.
Prerequisites
Before we start, make sure you have:
- Python 3.6 or newer installed
- Basic knowledge of Python
- Understanding of HTML (helpful but not required)
- A code editor of your choice
What You'll Learn
- Setting up a Flask environment
- Creating your first Flask application
- Handling routes and URL patterns
- Working with templates
- Processing form data
- Managing sessions and cookies
Setting Up Flask
First, let's install Flask using pip:
pip install flask
After installation, you can verify it by checking the version:
python -c "import flask; print(flask.__version__)"
Your First Flask Application
Let's create a simple "Hello, World!" application to understand the basic structure of a Flask app.
Create a new file named app.py
:
from flask import Flask
# Create a Flask application instance
app = Flask(__name__)
# Define a route for the root URL
@app.route('/')
def hello_world():
return 'Hello, World!'
# Run the application if this file is executed
if __name__ == '__main__':
app.run(debug=True)
Run this application:
python app.py
Output:
* Serving Flask app 'app'
* Debug mode: on
* Running on http://127.0.0.1:5000 (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 123-456-789
Now, open your web browser and navigate to http://127.0.0.1:5000/
. You should see "Hello, World!" displayed.
Understanding the Basic Flask Components
Let's break down what's happening in our example:
1. Application Instance
app = Flask(__name__)
This creates a Flask application instance. The __name__
parameter is a Python predefined variable representing the name of the current module. Flask uses this to determine the root path of the application.
2. Routes
@app.route('/')
def hello_world():
return 'Hello, World!'
The @app.route
decorator tells Flask what URL should trigger our function. In this case, the root URL /
will execute the hello_world()
function.
3. Running the Application
if __name__ == '__main__':
app.run(debug=True)
This code runs the application if the script is executed directly (not imported). The debug=True
parameter enables debug mode, which provides helpful error messages and automatically reloads the server when code changes.
Defining Routes
Routes map URLs to specific functions in your application. Let's expand our example with more routes:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'Welcome to the Home Page!'
@app.route('/about')
def about():
return 'About Us Page'
@app.route('/user/<username>')
def show_user_profile(username):
return f'User: {username}'
@app.route('/post/<int:post_id>')
def show_post(post_id):
return f'Post ID: {post_id}'
if __name__ == '__main__':
app.run(debug=True)
In this example:
/
routes to the home function/about
routes to the about function/user/<username>
captures the username from the URL and passes it to the function/post/<int:post_id>
captures the post_id as an integer
HTTP Methods
By default, Flask routes respond only to GET requests. To handle other HTTP methods like POST, you need to specify them:
from flask import Flask, request
app = Flask(__name__)
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
return f"Received POST data: {request.form['username']}"
else:
return '''
<form method="post">
<input type="text" name="username">
<input type="submit" value="Login">
</form>
'''
if __name__ == '__main__':
app.run(debug=True)
In this example, the login
route handles both GET and POST requests. When you navigate to /login
, you see a form (GET request). When you submit the form, the same route processes the data (POST request).
Templates
Instead of returning raw strings, real applications use templates to generate HTML. Flask uses the Jinja2 template engine.
First, create a templates
folder in your project directory and add an HTML file named index.html
:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>Hello, {{ name }}!</h1>
<p>Welcome to Flask.</p>
</body>
</html>
Now modify your app to use this template:
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html', title='Flask Tutorial', name='World')
@app.route('/user/<username>')
def user_profile(username):
return render_template('index.html', title='User Profile', name=username)
if __name__ == '__main__':
app.run(debug=True)
The render_template()
function takes the name of a template and any variables you want to pass to it.
Static Files
For CSS, JavaScript, and images, Flask looks in a folder called static
. Create this folder in your project directory:
your_app/
├── app.py
├── templates/
│ └── index.html
└── static/
└── style.css
Add some CSS to style.css
:
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f0f0f0;
}
h1 {
color: #333;
}
Update your template to include this CSS:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<h1>Hello, {{ name }}!</h1>
<p>Welcome to Flask.</p>
</body>
</html>
The url_for()
function generates a URL to the given endpoint.
Request Data and Forms
Flask makes it easy to access form data. Let's create a simple contact form:
from flask import Flask, render_template, request, redirect, url_for
app = Flask(__name__)
@app.route('/contact', methods=['GET', 'POST'])
def contact():
if request.method == 'POST':
name = request.form.get('name')
email = request.form.get('email')
message = request.form.get('message')
# In a real app, you'd process this data (save to database, send email, etc.)
print(f"Received message from {name} ({email}): {message}")
return redirect(url_for('thank_you'))
return render_template('contact.html')
@app.route('/thank-you')
def thank_you():
return render_template('thank_you.html')
if __name__ == '__main__':
app.run(debug=True)
Create contact.html
in your templates folder:
<!DOCTYPE html>
<html>
<head>
<title>Contact Us</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<h1>Contact Us</h1>
<form method="post">
<div>
<label for="name">Name:</label>
<input type="text" id="name" name="name" required>
</div>
<div>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required>
</div>
<div>
<label for="message">Message:</label>
<textarea id="message" name="message" required></textarea>
</div>
<button type="submit">Send Message</button>
</form>
</body>
</html>
And thank_you.html
:
<!DOCTYPE html>
<html>
<head>
<title>Thank You</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<h1>Thank You!</h1>
<p>Your message has been received. We'll get back to you soon.</p>
<a href="{{ url_for('contact') }}">Back to Contact Form</a>
</body>
</html>
A Real-World Example: Todo Application
Let's build a simple TODO application that demonstrates many Flask concepts:
from flask import Flask, render_template, request, redirect, url_for, session
import os
app = Flask(__name__)
app.secret_key = os.urandom(24) # Required for session
# In-memory storage for todos (in a real app, use a database)
todos = []
@app.route('/')
def index():
return render_template('todo_index.html', todos=todos)
@app.route('/add', methods=['POST'])
def add():
todo = request.form.get('todo')
if todo:
todos.append({'task': todo, 'done': False})
return redirect(url_for('index'))
@app.route('/toggle/<int:todo_id>')
def toggle(todo_id):
if 0 <= todo_id < len(todos):
todos[todo_id]['done'] = not todos[todo_id]['done']
return redirect(url_for('index'))
@app.route('/delete/<int:todo_id>')
def delete(todo_id):
if 0 <= todo_id < len(todos):
del todos[todo_id]
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
Create todo_index.html
in your templates folder:
<!DOCTYPE html>
<html>
<head>
<title>Todo App</title>
<style>
body { font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; }
ul { list-style-type: none; padding: 0; }
li { margin: 10px 0; padding: 10px; border: 1px solid #ddd; border-radius: 4px; }
.done { text-decoration: line-through; background-color: #f8f8f8; }
form { margin-bottom: 20px; }
input[type="text"] { padding: 8px; width: 70%; }
button { padding: 8px 15px; background-color: #4CAF50; color: white; border: none; cursor: pointer; }
.actions { float: right; }
.actions a { margin-left: 10px; color: #666; text-decoration: none; }
</style>
</head>
<body>
<h1>Todo List</h1>
<form method="post" action="{{ url_for('add') }}">
<input type="text" name="todo" placeholder="Add a new task..." required>
<button type="submit">Add</button>
</form>
<ul>
{% for i, todo in enumerate(todos) %}
<li class="{{ 'done' if todo.done else '' }}">
{{ todo.task }}
<div class="actions">
<a href="{{ url_for('toggle', todo_id=i) }}">
{{ "☑" if todo.done else "☐" }}
</a>
<a href="{{ url_for('delete', todo_id=i) }}">🗑</a>
</div>
</li>
{% else %}
<li>No tasks yet! Add one above.</li>
{% endfor %}
</ul>
</body>
</html>
This Todo application demonstrates:
- Route handling
- Form processing
- Template rendering with conditionals and loops
- URL building with parameters
- Basic session management
Sessions and Cookies
Flask provides built-in support for sessions and cookies, allowing you to store data between requests:
from flask import Flask, session, redirect, url_for, request, render_template
app = Flask(__name__)
app.secret_key = 'your-secret-key' # Required for session
@app.route('/')
def index():
if 'username' in session:
return f'Logged in as {session["username"]}'
return 'You are not logged in'
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
<form method="post">
<p>Username: <input type=text name=username>
<p><input type=submit value=Login>
</form>
'''
@app.route('/logout')
def logout():
session.pop('username', None)
return redirect(url_for('index'))
if __name__ == '__main__':
app.run(debug=True)
Project Structure for Larger Applications
As your Flask application grows, you'll want to organize your code better. Here's a recommended structure:
my_flask_app/
├── run.py # Entry point to run the application
├── config.py # Configuration settings
├── requirements.txt # Project dependencies
├── app/
│ ├── __init__.py # Initialize the Flask app
│ ├── routes.py # Define routes
│ ├── models.py # Database models
│ ├── forms.py # Form definitions (with Flask-WTF)
│ ├── static/ # Static files (CSS, JS, images)
│ └── templates/ # HTML templates
└── tests/ # Test cases
├── __init__.py
└── test_routes.py
Summary
In this tutorial, we've covered the basics of Flask:
- Setting up a Flask application
- Creating routes and handling different HTTP methods
- Working with templates using Jinja2
- Including static files like CSS
- Processing form data
- Using sessions for user state
- Building a simple Todo application
Flask's simplicity and flexibility make it an excellent choice for both beginners and experienced developers. The micro-framework approach allows you to start small and add components as needed, rather than beginning with a large, complex framework.
Next Steps and Additional Resources
To continue your Flask journey:
- Learn about database integration with Flask-SQLAlchemy
- Explore form handling with Flask-WTF
- Study authentication with Flask-Login
- Investigate API development with Flask-RESTful
Recommended Resources:
- Official Flask Documentation
- Flask Mega-Tutorial by Miguel Grinberg
- Flask Web Development book by Miguel Grinberg
Exercises
To reinforce your learning, try these exercises:
- Modify the Todo app to store tasks in a JSON file instead of memory
- Create a simple blog application with posts and comments
- Build a REST API for the Todo application
- Add user authentication to the Todo app so each user has their own list
- Implement categories for the Todo items with color coding
Good luck with your Flask journey!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)