Skip to main content

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:

bash
pip install flask

After installation, you can verify it by checking the version:

bash
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:

python
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:

bash
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

python
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

python
@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

python
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:

python
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:

python
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:

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:

python
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:

css
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
background-color: #f0f0f0;
}

h1 {
color: #333;
}

Update your template to include this CSS:

html
<!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:

python
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:

html
<!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:

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:

python
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:

html
<!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:

python
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:

  1. Learn about database integration with Flask-SQLAlchemy
  2. Explore form handling with Flask-WTF
  3. Study authentication with Flask-Login
  4. Investigate API development with Flask-RESTful

Exercises

To reinforce your learning, try these exercises:

  1. Modify the Todo app to store tasks in a JSON file instead of memory
  2. Create a simple blog application with posts and comments
  3. Build a REST API for the Todo application
  4. Add user authentication to the Todo app so each user has their own list
  5. 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! :)