Flask Python Framework

Learn how to build lightweight and powerful web applications with Python's most popular micro-framework

Get Started

Why Flask?

🪶

Lightweight

Flask is a micro-framework that provides the essentials without imposing a specific structure or dependencies.

📚

Easy to Learn

With its simple and intuitive API, Flask is perfect for beginners and experienced developers alike.

🧩

Extensible

Start small and add only what you need with Flask's extensive ecosystem of extensions.

Flask Overview

Flask is a Python micro-framework for web development. Unlike comprehensive frameworks like Django, Flask provides the bare essentials with the flexibility to choose your components and structure your application as you see fit.

Route Matching
View Function
Template Rendering
Response

When a request comes to a Flask application:

  1. Flask matches the URL to a registered route
  2. The corresponding view function is executed
  3. The view function processes data and may render a template
  4. A response is returned to the client

Getting Started with Flask

Prerequisites

Before you start, make sure you have:

Installation

The recommended way to install Flask is using pip, the Python package manager, within a virtual environment:

# Create a virtual environment python -m venv venv # Activate the virtual environment # On Windows: venv\Scripts\activate # On macOS/Linux: source venv/bin/activate # Install Flask pip install flask
Tip: Always use a virtual environment for your Flask projects. This isolates dependencies for each project, preventing conflicts between different projects.

Your First Flask Application

Let's create a simple "Hello, World!" application:

# app.py from flask import Flask # Create a Flask application instance app = Flask(__name__) # Define a route and view function @app.route('/') def hello_world(): return 'Hello, World!' # Run the application if this file is executed directly if __name__ == '__main__': app.run(debug=True)

Save this code in a file named app.py and run it:

python app.py

You should now be able to visit http://127.0.0.1:5000/ in your browser and see "Hello, World!"

Understanding the Code

Tip: Debug mode enables auto-reload when code changes and provides helpful error pages. Always disable debug mode in production.

Routing and URL Handling

Basic Routing

Routes in Flask are defined using the @app.route decorator:

@app.route('/') def index(): return 'Home Page' @app.route('/about') def about(): return 'About Page'

Dynamic Routes

You can capture parts of the URL as variables:

@app.route('/user/') def show_user_profile(username): return f'User: {username}' @app.route('/post/') def show_post(post_id): return f'Post: {post_id}'

Flask supports these converter types:

HTTP Methods

By default, routes only respond to GET requests. You can specify which HTTP methods are allowed:

@app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': # Process the login form return process_login_form() else: # Show the login form return show_login_form()

URL Building

Flask provides a url_for() function to build URLs for specific functions:

from flask import url_for @app.route('/') def index(): # Generate URL for the show_user_profile function url = url_for('show_user_profile', username='john') return f'User profile URL: {url}'
Tip: Always use url_for() to generate URLs instead of hardcoding them. This makes your application more maintainable.

Redirects and Errors

Flask provides functions for redirecting and displaying error pages:

from flask import redirect, url_for, abort @app.route('/redirect-example') def redirect_example(): # Redirect to the index page return redirect(url_for('index')) @app.route('/private') def private(): # Return a 403 Forbidden error abort(403)

Templates with Jinja2

Template Basics

Flask uses Jinja2 as its template engine. Templates are HTML files with Jinja2 syntax for dynamic content. By convention, templates are stored in a templates folder:

myapp/ |- app.py |- templates/ |- index.html |- about.html

Rendering templates in Flask:

from flask import render_template @app.route('/') def index(): return render_template('index.html', title='Home Page')

Jinja2 Syntax

Jinja2 provides several types of delimiters:

A simple Jinja2 template (index.html):

{{ title }}

Welcome to {{ title }}

{% if user %}

Hello, {{ user.username }}!

{% else %}

Hello, Guest!

{% endif %}

Posts

    {% for post in posts %}
  • {{ post.title }} - {{ post.author }}
  • {% else %}
  • No posts available.
  • {% endfor %}

Using this template in a view function:

@app.route('/') def index(): user = {'username': 'John'} posts = [ {'title': 'First Post', 'author': 'John'}, {'title': 'Second Post', 'author': 'Jane'} ] return render_template('index.html', title='Home', user=user, posts=posts)

Template Inheritance

Jinja2 supports template inheritance, which allows you to build a base template and extend it in child templates:

Base template (base.html):

{% block title %}{% endblock %} - My Website
{% block content %}{% endblock %}
© 2025 My Website

Child template (index.html):

{% extends "base.html" %} {% block title %}Home{% endblock %} {% block content %}

Welcome to My Website

This is the home page.

{% endblock %}

Static Files

Flask looks for static files (CSS, JavaScript, images) in a static folder:

myapp/ |- app.py |- static/ |- style.css |- script.js |- images/ |- logo.png |- templates/ |- base.html |- index.html

Referencing static files in templates:

Logo

Handling Forms

Basic Form Handling

Flask provides access to form data through the request object:

from flask import request @app.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': username = request.form.get('username') password = request.form.get('password') # Process login (omitted) return f'Logged in as {username}' # If GET request, show the login form return '''

'''

Flask-WTF for Forms

Flask-WTF is an extension that integrates WTForms with Flask, providing more structured form handling with validation:

pip install flask-wtf

Defining a form class:

from flask_wtf import FlaskForm from wtforms import StringField, PasswordField, SubmitField from wtforms.validators import DataRequired, Email, Length class LoginForm(FlaskForm): username = StringField('Username', validators=[DataRequired()]) password = PasswordField('Password', validators=[DataRequired(), Length(min=8)]) submit = SubmitField('Log In')

Using the form in a view function:

from flask import render_template, flash, redirect, url_for app.config['SECRET_KEY'] = 'your-secret-key' # Required for CSRF protection @app.route('/login', methods=['GET', 'POST']) def login(): form = LoginForm() if form.validate_on_submit(): # Form was submitted and is valid username = form.username.data password = form.password.data # Process login (omitted) flash(f'Login requested for user {username}') return redirect(url_for('index')) # Either GET request or invalid form submission return render_template('login.html', form=form)

Template for rendering the form (login.html):

{% extends "base.html" %} {% block content %}

Login

{% with messages = get_flashed_messages() %} {% if messages %}
    {% for message in messages %}
  • {{ message }}
  • {% endfor %}
{% endif %} {% endwith %}
{{ form.hidden_tag() }}
{{ form.username.label }} {{ form.username() }} {% if form.username.errors %}
    {% for error in form.username.errors %}
  • {{ error }}
  • {% endfor %}
{% endif %}
{{ form.password.label }} {{ form.password() }} {% if form.password.errors %}
    {% for error in form.password.errors %}
  • {{ error }}
  • {% endfor %}
{% endif %}
{{ form.submit() }}
{% endblock %}
Tip: Always include {{ form.hidden_tag() }} in your form template. This generates a hidden field with a CSRF token for security.

Database Integration

Flask-SQLAlchemy

Flask-SQLAlchemy is an extension that adds SQLAlchemy support to Flask, making it easier to work with databases:

pip install flask-sqlalchemy

Setting up SQLAlchemy:

from flask import Flask from flask_sqlalchemy import SQLAlchemy app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app)

Defining Models

Models are Python classes that represent database tables:

class User(db.Model): id = db.Column(db.Integer, primary_key=True) username = db.Column(db.String(80), unique=True, nullable=False) email = db.Column(db.String(120), unique=True, nullable=False) posts = db.relationship('Post', backref='author', lazy=True) def __repr__(self): return f'' class Post(db.Model): id = db.Column(db.Integer, primary_key=True) title = db.Column(db.String(100), nullable=False) content = db.Column(db.Text, nullable=False) user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False) def __repr__(self): return f''

Creating the Database

Create the database tables based on your models:

# Create tables db.create_all()

Basic CRUD Operations

Performing Create, Read, Update, Delete operations with SQLAlchemy:

# Create user = User(username='john', email='john@example.com') db.session.add(user) db.session.commit() # Read all_users = User.query.all() user = User.query.filter_by(username='john').first() user_by_id = User.query.get(1) # Update user = User.query.get(1) user.username = 'john_updated' db.session.commit() # Delete user = User.query.get(1) db.session.delete(user) db.session.commit()

Using Models in Views

Integrating database models with Flask views:

@app.route('/users') def list_users(): users = User.query.all() return render_template('users.html', users=users) @app.route('/user/') def user_detail(user_id): user = User.query.get_or_404(user_id) return render_template('user_detail.html', user=user) @app.route('/create_user', methods=['GET', 'POST']) def create_user(): if request.method == 'POST': username = request.form.get('username') email = request.form.get('email') user = User(username=username, email=email) db.session.add(user) db.session.commit() flash('User created successfully!') return redirect(url_for('list_users')) return render_template('create_user.html')

Migrations with Flask-Migrate

As your application evolves, you'll need to modify your database schema. Flask-Migrate (based on Alembic) helps manage database migrations:

pip install flask-migrate

Setting up Flask-Migrate:

from flask import Flask from flask_sqlalchemy import SQLAlchemy from flask_migrate import Migrate app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False db = SQLAlchemy(app) migrate = Migrate(app, db) # Define models here

Using Flask-Migrate from the command line:

# Initialize migrations flask db init # Create a migration after model changes flask db migrate -m "Add user table" # Apply migrations to the database flask db upgrade # Rollback migrations if needed flask db downgrade

Structuring Large Applications with Blueprints

What are Blueprints?

Blueprints are a way to organize your Flask application into modular components. They help you split your application into smaller, reusable parts that can be registered with the main application.

Creating a Blueprint

Let's create a blueprint for user-related routes:

# users/routes.py from flask import Blueprint, render_template, redirect, url_for, flash, request from myapp.models import User from myapp.extensions import db users_bp = Blueprint('users', __name__, url_prefix='/users') @users_bp.route('/') def list_users(): users = User.query.all() return render_template('users/list.html', users=users) @users_bp.route('/') def user_detail(user_id): user = User.query.get_or_404(user_id) return render_template('users/detail.html', user=user) @users_bp.route('/create', methods=['GET', 'POST']) def create_user(): if request.method == 'POST': username = request.form.get('username') email = request.form.get('email') user = User(username=username, email=email) db.session.add(user) db.session.commit() flash('User created successfully!') return redirect(url_for('users.list_users')) return render_template('users/create.html')

Registering Blueprints

In your application factory or main file:

# app.py or __init__.py from flask import Flask from myapp.users.routes import users_bp from myapp.posts.routes import posts_bp from myapp.extensions import db def create_app(): app = Flask(__name__) app.config.from_object('config.Config') # Initialize extensions db.init_app(app) # Register blueprints app.register_blueprint(users_bp) app.register_blueprint(posts_bp) return app

Recommended Project Structure

For larger Flask applications, a modular structure using blueprints is recommended:

myapp/ |- __init__.py # Application factory |- extensions.py # Flask extensions instances |- models.py # Database models |- config.py # Configuration |- users/ |- __init__.py |- routes.py # User blueprint |- forms.py # User-related forms |- posts/ |- __init__.py |- routes.py # Post blueprint |- forms.py # Post-related forms |- auth/ |- __init__.py |- routes.py # Authentication blueprint |- forms.py # Authentication forms |- templates/ |- base.html # Base template |- users/ # User templates |- posts/ # Post templates |- auth/ # Auth templates |- static/ |- css/ |- js/ |- images/ |- tests/ # Unit tests |- run.py # Application entry point

Deployment

Preparing for Production

Before deploying a Flask application, make sure to:

Deployment Options

1. Traditional Server with Gunicorn and Nginx

# Install Gunicorn pip install gunicorn # Run with Gunicorn gunicorn -w 4 -b 127.0.0.1:5000 "myapp:create_app()"

Configure Nginx as a reverse proxy:

server { listen 80; server_name example.com; location / { proxy_pass http://127.0.0.1:5000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

2. Docker Deployment

Create a Dockerfile:

FROM python:3.9-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "myapp:create_app()"]

3. Platform as a Service (PaaS)

For simpler deployments, consider using services like:

Popular Flask Extensions

Flask-Login

User session management for Flask, providing user authentication and "remember me" functionality.

pip install flask-login

Flask-RESTful

Extension for quickly building REST APIs in Flask.

pip install flask-restful

Flask-Admin

Ready-to-use admin interface for Flask that can integrate with SQLAlchemy, MongoDB, and more.

pip install flask-admin

Flask-Mail

Makes sending emails from Flask applications simple.

pip install flask-mail

Flask-Caching

Adds caching support to your Flask application.

pip install flask-caching

Flask-JWT-Extended

JWT authentication support for Flask applications.

pip install flask-jwt-extended

Additional Resources

Official Flask Documentation

Comprehensive and well-organized documentation for Flask.

Visit

Flask Mega-Tutorial

An in-depth tutorial by Miguel Grinberg covering all aspects of Flask.

Visit

Flask Web Development

Book by Miguel Grinberg on building web applications with Flask.

Visit
Reading Progress