Documentation

Welcome to the comprehensive Flask documentation. Here, you'll find detailed guides and tutorials for building web applications with Flask.

Introduction to Flask

Flask is a lightweight WSGI web application framework. It is designed to make getting started quick and easy, with the ability to scale up to complex applications.

Key features of Flask:

  • Lightweight - Minimal core with extensions available
  • Werkzeug - WSGI utility library for Python
  • Jinja2 - Template engine for Python
  • Flexible - No database or form validation layers included
  • Extensible - Rich ecosystem of extensions
  • RESTful - Built-in support for REST request dispatching
Setup and Installation

Virtual Environment

Always use a virtual environment for Flask projects:


# Create virtual environment
python -m venv venv

# Activate on Windows
venv\Scripts\activate

# Activate on macOS/Linux
source venv/bin/activate

# Deactivate
deactivate

Install Flask


# Install Flask
pip install Flask

# Install additional useful packages
pip install Flask-SQLAlchemy Flask-Migrate Flask-WTF Flask-Login Flask-Mail python-dotenv

Verify Installation


# test_flask.py
import flask
print(flask.__version__)
Basic Flask Application

Minimal Flask App


# app.py
from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

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

Running the Application


# Run the development server
python app.py

# Or using flask command
flask run

# With custom host and port
flask run --host=0.0.0.0 --port=5000

Application Factory Pattern


# __init__.py
from flask import Flask

def create_app(config_name='development'):
    app = Flask(__name__)
    
    # Load configuration
    app.config.from_object(f'config.{config_name}')
    
    # Register blueprints
    from app.routes import main_bp
    app.register_blueprint(main_bp)
    
    return app

# run.py
from app import create_app

app = create_app()

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

Basic Routes


from flask import Flask

app = Flask(__name__)

@app.route('/')
def index():
    return 'Index Page'

@app.route('/hello')
def hello():
    return 'Hello, World!'

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

@app.route('/post/')
def show_post(post_id):
    return f'Post ID: {post_id}'

@app.route('/path/')
def show_subpath(subpath):
    return f'Subpath: {subpath}'

HTTP Methods


from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        return handle_login()
    else:
        return show_login_form()

def handle_login():
    username = request.form['username']
    password = request.form['password']
    # Process login
    return f'Logged in as {username}'

def show_login_form():
    return '''
        
'''

URL Building


from flask import url_for

@app.route('/profile')
def profile():
    return 'Profile Page'

@app.route('/dashboard')
def dashboard():
    # Generate URL for profile endpoint
    profile_url = url_for('profile')
    return f'Dashboard - Go to Profile'

# Dynamic URL building
@app.route('/user/')
def user_profile(username):
    edit_url = url_for('edit_user', username=username)
    return f'User: {username} - Edit'

@app.route('/user//edit')
def edit_user(username):
    return f'Edit User: {username}'

Blueprints


# auth.py
from flask import Blueprint, render_template

auth_bp = Blueprint('auth', __name__, url_prefix='/auth')

@auth_bp.route('/login')
def login():
    return render_template('login.html')

@auth_bp.route('/register')
def register():
    return render_template('register.html')

# main.py
from flask import Flask
from auth import auth_bp

app = Flask(__name__)
app.register_blueprint(auth_bp)

# Or with URL prefix
app.register_blueprint(auth_bp, url_prefix='/auth')
Templates and Jinja2

Basic Templates






    
    
    {% block title %}My App{% endblock %}
    


    
{% block content %}{% endblock %}

© 2023 My Flask App



{% extends "base.html" %}

{% block title %}Home - {% endblock %}

{% block content %}

Welcome to My Flask App

This is the home page.

{% if user %}

Hello, {{ user.name }}!

{% else %}

Please log in.

{% endif %}
    {% for item in items %}
  • {{ item.name }} - ${{ item.price }}
  • {% endfor %}
{% endblock %}

Template Inheritance


from flask import render_template

@app.route('/')
def index():
    user = {'name': 'John Doe', 'email': 'john@example.com'}
    items = [
        {'name': 'Product 1', 'price': 10.99},
        {'name': 'Product 2', 'price': 24.99},
        {'name': 'Product 3', 'price': 5.99}
    ]
    return render_template('index.html', user=user, items=items)

Jinja2 Filters



{{ text|capitalize }}

{{ text|upper }}

{{ text|lower }}

{{ text|title }}

{{ number|round(2) }}

{{ date|strftime('%Y-%m-%d') }}

{{ text|truncate(50) }}

{{ html|safe }}

{{ price|currency }}

{{ date|timesince }}

Custom Filters


# app.py
from flask import Flask

app = Flask(__name__)

@app.template_filter('currency')
def currency_filter(value):
    return f"${value:.2f}"

@app.template_filter('timesince')
def timesince_filter(value):
    from datetime import datetime
    now = datetime.utcnow()
    diff = now - value
    return f"{diff.days} days ago"

# Or using add_template_filter
def format_date(value, format='%Y-%m-%d'):
    return value.strftime(format)

app.jinja_env.filters['format_date'] = format_date
Static Files

Static File Structure


myapp/
├── static/
│   ├── css/
│   │   ├── style.css
│   │   └── bootstrap.min.css
│   ├── js/
│   │   ├── app.js
│   │   └── jquery.min.js
│   ├── images/
│   │   ├── logo.png
│   │   └── banner.jpg
│   └── fonts/
└── templates/

Accessing Static Files


<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
<img src="{{ url_for('static', filename='images/logo.png') }}" alt="Logo">

<!-- With versioning for cache busting -->
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css', v='1.0.0') }}">
Forms and WTForms

Basic Forms


from flask import Flask, render_template, request, redirect, url_for, flash

app = Flask(__name__)
app.secret_key = 'your-secret-key'

@app.route('/contact', methods=['GET', 'POST'])
def contact():
    if request.method == 'POST':
        name = request.form['name']
        email = request.form['email']
        message = request.form['message']
        
        # Process form data
        flash('Thank you for your message!', 'success')
        return redirect(url_for('contact'))
    
    return render_template('contact.html')


{% extends "base.html" %}

{% block content %}

Contact Us

{% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %}
{{ message }}
{% endfor %} {% endif %} {% endwith %}
{% endblock %}

WTForms Integration


# forms.py
from flask_wtf import FlaskForm
from wtforms import StringField, TextAreaField, SubmitField
from wtforms.validators import DataRequired, Email, Length

class ContactForm(FlaskForm):
    name = StringField('Name', validators=[DataRequired(), Length(min=2, max=50)])
    email = StringField('Email', validators=[DataRequired(), Email()])
    message = TextAreaField('Message', validators=[DataRequired(), Length(min=10)])
    submit = SubmitField('Send Message')

# app.py
from flask import Flask, render_template, request, redirect, url_for, flash
from forms import ContactForm

app = Flask(__name__)
app.secret_key = 'your-secret-key'

@app.route('/contact', methods=['GET', 'POST'])
def contact():
    form = ContactForm()
    
    if form.validate_on_submit():
        name = form.name.data
        email = form.email.data
        message = form.message.data
        
        # Process form data
        flash('Thank you for your message!', 'success')
        return redirect(url_for('contact'))
    
    return render_template('contact.html', form=form)


{% extends "base.html" %}

{% block content %}

Contact Us

{% with messages = get_flashed_messages(with_categories=true) %} {% if messages %} {% for category, message in messages %}
{{ message }}
{% endfor %} {% endif %} {% endwith %}
{{ form.hidden_tag() }}
{{ form.name.label(class="form-control-label") }} {{ form.name(class="form-control") }} {% if form.name.errors %}
{% for error in form.name.errors %} {{ error }} {% endfor %}
{% endif %}
{{ form.email.label(class="form-control-label") }} {{ form.email(class="form-control") }} {% if form.email.errors %}
{% for error in form.email.errors %} {{ error }} {% endfor %}
{% endif %}
{{ form.message.label(class="form-control-label") }} {{ form.message(class="form-control") }} {% if form.message.errors %}
{% for error in form.message.errors %} {{ error }} {% endfor %}
{% endif %}
{{ form.submit(class="btn btn-primary") }}
{% endblock %}
Database Integration

Flask-SQLAlchemy Setup


# models.py
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime

db = SQLAlchemy()

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)
    password_hash = db.Column(db.String(128))
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    
    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)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
    
    def __repr__(self):
        return f''

# app.py
from flask import Flask
from models import db, User, Post

app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///app.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False

db.init_app(app)

# Create tables
with app.app_context():
    db.create_all()

CRUD Operations


from flask import render_template, request, redirect, url_for, flash
from models import db, User
from werkzeug.security import generate_password_hash, check_password_hash

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        email = request.form['email']
        password = request.form['password']
        
        # Check if user already exists
        if User.query.filter_by(username=username).first():
            flash('Username already exists', 'error')
            return redirect(url_for('register'))
        
        # Create new user
        user = User(
            username=username,
            email=email,
            password_hash=generate_password_hash(password)
        )
        db.session.add(user)
        db.session.commit()
        
        flash('Registration successful! Please log in.', 'success')
        return redirect(url_for('login'))
    
    return render_template('register.html')

@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('/user//edit', methods=['GET', 'POST'])
def edit_user(user_id):
    user = User.query.get_or_404(user_id)
    
    if request.method == 'POST':
        user.username = request.form['username']
        user.email = request.form['email']
        db.session.commit()
        flash('User updated successfully!', 'success')
        return redirect(url_for('user_detail', user_id=user_id))
    
    return render_template('edit_user.html', user=user)

@app.route('/user//delete', methods=['POST'])
def delete_user(user_id):
    user = User.query.get_or_404(user_id)
    db.session.delete(user)
    db.session.commit()
    flash('User deleted successfully!', 'success')
    return redirect(url_for('list_users'))
Authentication and Authorization

Flask-Login Setup


# auth.py
from flask_login import LoginManager, UserMixin, login_user, logout_user, login_required, current_user

login_manager = LoginManager()

class User(UserMixin, 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)
    password_hash = db.Column(db.String(128))
    
    def set_password(self, password):
        self.password_hash = generate_password_hash(password)
    
    def check_password(self, password):
        return check_password_hash(password, self.password_hash)

# app.py
from flask_login import LoginManager, login_user, logout_user, login_required, current_user

app = Flask(__name__)
login_manager = LoginManager()
login_manager.login_view = 'login'
login_manager.logout_view = 'logout'

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(int(user_id))

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
        
        if user and user.check_password(password):
            login_user(user)
            flash('Logged in successfully!', 'success')
            return redirect(url_for('dashboard'))
        else:
            flash('Invalid username or password', 'error')
    
    return render_template('login.html')

@app.route('/logout')
@login_required
def logout():
    logout_user()
    flash('You have been logged out.', 'info')
    return redirect(url_for('index'))

@app.route('/dashboard')
@login_required
def dashboard():
    return render_template('dashboard.html', user=current_user)

Role-Based Authorization


# models.py
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)
    password_hash = db.Column(db.String(128))
    role = db.Column(db.String(20), default='user')  # 'user', 'admin', 'moderator'
    
    def is_admin(self):
        return self.role == 'admin'

# decorators.py
from functools import wraps
from flask import abort, redirect, url_for, flash
from flask_login import current_user

def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated or not current_user.is_admin():
            flash('Admin access required!', 'error')
            return redirect(url_for('index'))
        return f(*args, **kwargs)
    return decorated_function

# app.py
@app.route('/admin')
@admin_required
def admin_panel():
    return render_template('admin.html')
Building REST APIs

Basic API Structure


from flask import Flask, jsonify, request
from models import db, User, Post

app = Flask(__name__)

@app.route('/api/users', methods=['GET'])
def get_users():
    users = User.query.all()
    return jsonify([{
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'created_at': user.created_at.isoformat()
    } for user in users])

@app.route('/api/users', methods=['POST'])
def create_user():
    data = request.get_json()
    
    if not data or not data.get('username') or not data.get('password'):
        return jsonify({'error': 'Username and password required'}), 400
    
    # Check if user already exists
    if User.query.filter_by(username=data['username']).first():
        return jsonify({'error': 'Username already exists'}), 409
    
    user = User(
        username=data['username'],
        email=data.get('email', ''),
        password_hash=generate_password_hash(data['password'])
    )
    db.session.add(user)
    db.session.commit()
    
    return jsonify({
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'created_at': user.created_at.isoformat()
    }), 201

@app.route('/api/users/', methods=['GET'])
def get_user(user_id):
    user = User.query.get_or_404(user_id)
    return jsonify({
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'created_at': user.created_at.isoformat()
    })

@app.route('/api/users/', methods=['PUT'])
def update_user(user_id):
    user = User.query.get_or_404(user_id)
    data = request.get_json()
    
    if data.get('username'):
        user.username = data['username']
    if data.get('email'):
        user.email = data['email']
    
    db.session.commit()
    
    return jsonify({
        'id': user.id,
        'username': user.username,
        'email': user.email,
        'updated_at': datetime.utcnow().isoformat()
    })

@app.route('/api/users/', methods=['DELETE'])
def delete_user(user_id):
    user = User.query.get_or_404(user_id)
    db.session.delete(user)
    db.session.commit()
    
    return jsonify({'message': 'User deleted successfully'})

API Versioning


# api/v1/users.py
from flask import Blueprint

v1_bp = Blueprint('api_v1', __name__, url_prefix='/api/v1')

@v1_bp.route('/users', methods=['GET'])
def get_users_v1():
    users = User.query.all()
    return jsonify([{
        'id': user.id,
        'username': user.username,
        'email': user.email
    } for user in users])

# api/v2/users.py
v2_bp = Blueprint('api_v2', __name__, url_prefix='/api/v2')

@v2_bp.route('/users', methods=['GET'])
def get_users_v2():
    users = User.query.all()
    return jsonify({
        'users': [{
            'id': user.id,
            'username': user.username,
            'email': user.email,
            'created_at': user.created_at.isoformat(),
            'posts_count': len(user.posts)
        } for user in users],
        'total': len(users)
    })

# app.py
from api.v1.users import v1_bp
from api.v2.users import v2_bp

app.register_blueprint(v1_bp)
app.register_blueprint(v2_bp)
Testing Flask Applications

Unit Testing with pytest


# Install testing dependencies
pip install pytest pytest-flask

# test_app.py
import pytest
from app import create_app

@pytest.fixture
def app():
    app = create_app('testing')
    with app.app_context():
        yield app

@pytest.fixture
def client(app):
    return app.test_client()

def test_index(client):
    response = client.get('/')
    assert response.status_code == 200
    assert b'Hello, World!' in response.data

def test_login(client):
    response = client.post('/login', data={
        'username': 'testuser',
        'password': 'testpass'
    })
    assert response.status_code == 302  # Redirect

def test_register(client):
    response = client.post('/register', data={
        'username': 'newuser',
        'email': 'newuser@example.com',
        'password': 'password123'
    })
    assert response.status_code == 302  # Redirect

Integration Testing


# test_api.py
import json
import pytest
from app import create_app

@pytest.fixture
def app():
    app = create_app('testing')
    with app.app_context():
        db.create_all()
        yield app

@pytest.fixture
def client(app):
    return app.test_client()

def test_get_users(client):
    response = client.get('/api/users')
    assert response.status_code == 200
    data = json.loads(response.data)
    assert isinstance(data, list)

def test_create_user(client):
    user_data = {
        'username': 'testuser',
        'password': 'testpass',
        'email': 'test@example.com'
    }
    response = client.post('/api/users',
                         data=json.dumps(user_data),
                         content_type='application/json')
    assert response.status_code == 201
    data = json.loads(response.data)
    assert data['username'] == 'testuser'
    assert data['email'] == 'test@example.com'
Deployment

Production Configuration


# config.py
import os

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY') or 'dev-secret-key'
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or 'sqlite:///app.db'
    SQLALCHEMY_TRACK_MODIFICATIONS = False

class DevelopmentConfig(Config):
    DEBUG = True

class ProductionConfig(Config):
    DEBUG = False
    # Add production-specific settings
    SESSION_COOKIE_SECURE = True
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SAMESITE = 'Lax'

class TestingConfig(Config):
    TESTING = True
    SQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'
    WTF_CSRF_ENABLED = False

config = {
    'development': DevelopmentConfig,
    'production': ProductionConfig,
    'testing': TestingConfig
}

Gunicorn Deployment


# Install Gunicorn
pip install gunicorn

# Run with Gunicorn
gunicorn -w 4 -b 0.0.0.0:8000 app:app

# Or with a configuration file
gunicorn -c gunicorn.conf.py app:app

# gunicorn.conf.py
bind = "0.0.0.0:8000"
workers = 4
worker_class = "sync"
worker_connections = 1000
timeout = 30
keepalive = 2
max_requests = 1000
max_requests_jitter = 100
preload_app = True

Docker Deployment


# Dockerfile
FROM python:3.9-slim

WORKDIR /app

# Install system dependencies
RUN apt-get update && apt-get install -y \
    gcc \
    && rm -rf /var/lib/apt/lists/*

# Install Python dependencies
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copy application code
COPY . .

# Expose port
EXPOSE 5000

# Run the application
CMD ["gunicorn", "-b", "0.0.0.0:5000", "app:app"]

# docker-compose.yml
version: '3.8'

services:
  web:
    build: .
    ports:
      - "5000:5000"
    environment:
      - FLASK_ENV=production
      - DATABASE_URL=postgresql://user:password@db:5432/appdb
    depends_on:
      - db
  
  db:
    image: postgres:13
    environment:
      - POSTGRES_DB=appdb
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:
Flask Best Practices

Project Structure


myflaskapp/
├── app/
│   ├── __init__.py
│   ├── models.py
│   ├── routes/
│   │   ├── __init__.py
│   │   ├── main.py
│   │   ├── auth.py
│   │   └── api.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── index.html
│   │   ├── auth/
│   │   └── errors/
│   ├── static/
│   │   ├── css/
│   │   ├── js/
│   │   └── images/
│   └── forms.py
├── migrations/
├── tests/
│   ├── test_app.py
│   ├── test_models.py
│   └── test_routes/
├── config.py
├── requirements.txt
├── run.py
└── README.md

Configuration Management


# Use environment variables for configuration
import os
from dotenv import load_dotenv

load_dotenv()

class Config:
    SECRET_KEY = os.environ.get('SECRET_KEY')
    SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')
    MAIL_SERVER = os.environ.get('MAIL_SERVER')
    MAIL_PORT = os.environ.get('MAIL_PORT', 587)
    MAIL_USE_TLS = os.environ.get('MAIL_USE_TLS', 'true')
    MAIL_USERNAME = os.environ.get('MAIL_USERNAME')
    MAIL_PASSWORD = os.environ.get('MAIL_PASSWORD')

# .env file (never commit to version control)
SECRET_KEY=your-secret-key-here
DATABASE_URL=postgresql://user:password@localhost:5432/dbname
MAIL_SERVER=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=your-email@gmail.com
MAIL_PASSWORD=your-app-password

Error Handling


# errors.py
from flask import render_template

def not_found_error(error):
    return render_template('errors/404.html'), 404

def internal_error(error):
    return render_template('errors/500.html'), 500

# app.py
from flask import Flask
from errors import not_found_error, internal_error

app = Flask(__name__)

@app.errorhandler(404)
def not_found(error):
    return not_found_error(error)

@app.errorhandler(500)
def internal_error(error):
    return internal_error(error)

# Custom error handlers
@app.errorhandler(403)
def forbidden(error):
    return render_template('errors/403.html'), 403

Security Best Practices


# Security considerations
from flask import Flask
from flask_talisman import Talisman
from flask_wtf.csrf import CSRFProtect

app = Flask(__name__)

# Enable CSRF protection
CSRFProtect(app)

# Enable security headers
Talisman(app, force_https=True)

# Content Security Policy
csp = {
    'default-src': "'self'",
    'script-src': "'self'",
    'style-src': "'self' 'unsafe-inline'",
    'img-src': "'self' data:",
    'font-src': "'self'",
    'connect-src': "'self'"
}

# Use HTTPS in production
if app.config.get('ENV') == 'production':
    app.config.update(
        SESSION_COOKIE_SECURE=True,
        SESSION_COOKIE_HTTPONLY=True,
        SESSION_COOKIE_SAMESITE='Lax',
        PERMANENT_SESSION_LIFETIME=3600
    )
Popular Flask Extensions

Flask-SQLAlchemy


# Database models and relationships
class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True)
    posts = db.relationship('Post', backref='author', lazy='dynamic')

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)
    user_id = db.Column(db.Integer, db.ForeignKey('user.id'))
    author = db.relationship('User', backref='posts')

# Database migrations
from flask_migrate import Migrate

migrate = Migrate(app, db)

Flask-Mail


from flask_mail import Mail, Message

app.config['MAIL_SERVER'] = 'smtp.gmail.com'
app.config['MAIL_PORT'] = 587
app.config['MAIL_USE_TLS'] = True
app.config['MAIL_USERNAME'] = 'your-email@gmail.com'
app.config['MAIL_PASSWORD'] = 'your-password'

mail = Mail(app)

@app.route('/send-email')
def send_email():
    msg = Message(
        'Hello',
        sender='from@example.com',
        recipients=['to@example.com'],
        body='This is a test email'
    )
    mail.send(msg)
    return 'Email sent!'

Flask-RESTful


from flask_restful import Api, Resource
from flask import jsonify

class UserResource(Resource):
    def get(self):
        users = User.query.all()
        return jsonify([{
            'id': user.id,
            'username': user.username,
            'email': user.email
        } for user in users])

    def post(self):
        data = request.get_json()
        user = User(username=data['username'])
        db.session.add(user)
        db.session.commit()
        return jsonify({'id': user.id}), 201

api.add_resource(UserResource, '/api/users')
Real-World Examples

File Upload Service


import os
from flask import Flask, request, redirect, url_for, flash
from werkzeug.utils import secure_filename

app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = 'uploads'
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)

ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif'}

def allowed_file(filename):
    return '.' in filename and \
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/upload', methods=['GET', 'POST'])
def upload_file():
    if request.method == 'POST':
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        
        file = request.files['file']
        if file.filename == '':
            flash('No selected file')
            return redirect(request.url)
        
        if file and allowed_file(file.filename):
            filename = secure_filename(file.filename)
            file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
            flash('File successfully uploaded')
            return redirect(url_for('uploaded_file',
                                   filename=filename))
    
    return render_template('upload.html')

@app.route('/uploads/')
def uploaded_file(filename):
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)

WebSocket Support


# Install Flask-SocketIO
pip install flask-socketio

# app.py
from flask import Flask, render_template
from flask_socketio import SocketIO, emit

app = Flask(__name__)
socketio = SocketIO(app)

@app.route('/')
def index():
    return render_template('index.html')

@socketio.on('connect')
def handle_connect():
    print('Client connected')
    emit('server_response', {'data': 'Connected!'})

@socketio.on('disconnect')
def handle_disconnect():
    print('Client disconnected')

if __name__ == '__main__':
    socketio.run(app, debug=True)





    Flask-SocketIO Test
    


    

Flask-SocketIO Test

Conclusion

This comprehensive Flask documentation covers essential concepts from basics to advanced topics. Flask provides a solid foundation for building web applications quickly and efficiently.

Key takeaways:

  • Flask is lightweight and extensible
  • Use blueprints for organizing large applications
  • Always use virtual environments for dependency management
  • Implement proper authentication and authorization
  • Write tests to ensure application reliability
  • Follow security best practices in production
  • Use appropriate extensions for common tasks

Continue learning by building real-world applications, exploring the Flask ecosystem, and staying engaged with the community. Happy coding with Flask!