What is Flask – a comprehensive guide to the Python web framework
Introduction to Flask
Flask — a minimalist web framework in Python designed for building web applications and REST APIs. It provides a simple and flexible structure that allows rapid development of both prototypes and full‑featured web applications. Flask is built on the WSGI toolkit Werkzeug and uses the Jinja2 templating system.
Created by Armin Ronacher in 2010, Flask gained popularity thanks to the philosophy “do one thing, and do it well”. Unlike heavier frameworks, Flask provides only the essential basics, allowing developers to choose their own components for each project.
Main features of Flask
Minimalist and extensible approach
Flask follows the micro‑framework principle, offering core functionality and allowing extensions via plugins and add‑ons.
Built‑in routing and request handling
The framework provides an intuitive routing system with support for various HTTP methods and URL parameters.
Jinja2 template support
Integration with the powerful Jinja2 templating engine enables convenient work with HTML templates and dynamic content.
Ability to create REST APIs
Flask is well‑suited for building RESTful APIs thanks to JSON response support and flexible HTTP method handling.
Extension support
A rich ecosystem of extensions lets you add functionality for databases, authentication, forms, and much more.
Compatibility with Python 3.7+
Flask supports modern versions of Python and follows best development practices.
Installation and setup
Installation via pip
pip install flask
Verify installation
python -m flask --version
Create app.py and run
export FLASK_APP=app.py
flask run
For Windows:
set FLASK_APP=app.py
flask run
Creating the first application
Simple example app.py
from flask import Flask
app = Flask(__name__)
@app.route("/")
def home():
return "Welcome to Flask!"
if __name__ == '__main__':
app.run(debug=True)
Running the application
flask run
The application will be available at http://localhost:5000/
Routing and URLs
Basic routing
@app.route("/user/<username>")
def show_user_profile(username):
return f"User profile: {username}"
Typed routes
@app.route("/post/<int:post_id>")
def show_post(post_id):
return f"Post #{post_id}"
@app.route("/user/<path:subpath>")
def show_subpath(subpath):
return f"Subpath: {subpath}"
Supported parameter types
string– strings (default)int– integersfloat– floating‑point numberspath– strings containing “/”uuid– UUID strings
Working with HTTP methods
Handling different methods
@app.route("/data", methods=["GET", "POST", "PUT", "DELETE"])
def handle_data():
if request.method == "POST":
return "Data created"
elif request.method == "PUT":
return "Data updated"
elif request.method == "DELETE":
return "Data deleted"
return "Data retrieved"
Working with Jinja2 templates
Creating templates
Create a templates folder and an index.html file:
<!-- templates/index.html -->
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>Hello, {{ name }}!</h1>
<p>Today is {{ date.strftime('%d.%m.%Y') }}</p>
</body>
</html>
Using it in the app
from flask import render_template
from datetime import datetime
@app.route("/hello/<name>")
def hello(name):
return render_template("index.html",
name=name,
title="Greeting",
date=datetime.now())
Template inheritance
Base template base.html:
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Site{% endblock %}</title>
</head>
<body>
<nav>
<ul>
<li><a href="/">Home</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
<main>
{% block content %}{% endblock %}
</main>
</body>
</html>
Child template:
<!-- templates/home.html -->
{% extends "base.html" %}
{% block title %}Home – My Site{% endblock %}
{% block content %}
<h1>Welcome!</h1>
<p>This is the home page.</p>
{% endblock %}
Form handling and POST/GET methods
Simple form
from flask import request
@app.route("/form", methods=["GET", "POST"])
def form():
if request.method == "POST":
username = request.form["username"]
email = request.form["email"]
return f"Hello, {username}! Email: {email}"
return '''
<form method="post">
<input name="username" placeholder="Name" required>
<input name="email" type="email" placeholder="Email" required>
<input type="submit" value="Submit">
</form>
'''
File handling
from werkzeug.utils import secure_filename
import os
@app.route("/upload", methods=["GET", "POST"])
def upload_file():
if request.method == "POST":
if 'file' not in request.files:
return "No file selected"
file = request.files['file']
if file.filename == '':
return "No file selected"
if file:
filename = secure_filename(file.filename)
file.save(os.path.join('uploads', filename))
return f"File {filename} uploaded successfully"
return '''
<form method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="Upload">
</form>
'''
Working with databases
Using SQLAlchemy
pip install flask-sqlalchemy
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(20), unique=True, nullable=False)
email = db.Column(db.String(120), unique=True, nullable=False)
password_hash = db.Column(db.String(60), nullable=False)
posts = db.relationship('Post', backref='author', lazy=True)
def __repr__(self):
return f"User('{self.username}', '{self.email}')"
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)
date_posted = db.Column(db.DateTime, nullable=False, default=datetime.utcnow)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
def __repr__(self):
return f"Post('{self.title}', '{self.date_posted}')"
Creating the database
@app.before_first_request
def create_tables():
db.create_all()
Creating a REST API with Flask
Basic API
from flask import jsonify, request
@app.route("/api/users", methods=["GET"])
def get_users():
users = User.query.all()
return jsonify([{
'id': user.id,
'username': user.username,
'email': user.email
} for user in users])
@app.route("/api/users", methods=["POST"])
def create_user():
data = request.get_json()
if not data or 'username' not in data or 'email' not in data:
return jsonify({'error': 'Insufficient data'}), 400
user = User(
username=data['username'],
email=data['email'],
password_hash='hashed_password' # In a real app, hash the password
)
db.session.add(user)
db.session.commit()
return jsonify({
'message': 'User created',
'user': {
'id': user.id,
'username': user.username,
'email': user.email
}
}), 201
Using Flask-RESTful
pip install flask-restful
from flask_restful import Api, Resource
api = Api(app)
class UserListAPI(Resource):
def get(self):
users = User.query.all()
return [{'id': u.id, 'username': u.username} for u in users]
def post(self):
data = request.get_json()
user = User(username=data['username'], email=data['email'])
db.session.add(user)
db.session.commit()
return {'message': 'User created'}, 201
api.add_resource(UserListAPI, '/api/users')
Working with sessions and cookies
Session configuration
from flask import session
app.secret_key = 'your-secret-key-here' # Use os.urandom(24) in production
@app.route("/login", methods=["GET", "POST"])
def login():
if request.method == "POST":
username = request.form["username"]
password = request.form["password"]
# Simplified user check
user = User.query.filter_by(username=username).first()
if user and check_password_hash(user.password_hash, password):
session["user_id"] = user.id
session["username"] = user.username
return redirect(url_for("dashboard"))
else:
return "Invalid login credentials"
return '''
<form method="post">
<input name="username" placeholder="Username" required>
<input name="password" type="password" placeholder="Password" required>
<input type="submit" value="Log In">
</form>
'''
@app.route("/logout")
def logout():
session.pop("user_id", None)
session.pop("username", None)
return redirect(url_for("home"))
Cookie handling
from flask import make_response
@app.route("/set_cookie")
def set_cookie():
response = make_response("Cookie set")
response.set_cookie("username", "john_doe", max_age=60*60*24) # 24 hours
return response
@app.route("/get_cookie")
def get_cookie():
username = request.cookies.get("username", "Guest")
return f"Hello, {username}!"
Error handling and logging
Error handling
@app.errorhandler(404)
def page_not_found(error):
return render_template("404.html"), 404
@app.errorhandler(500)
def internal_error(error):
db.session.rollback()
return render_template("500.html"), 500
@app.errorhandler(403)
def forbidden(error):
return render_template("403.html"), 403
Logging configuration
import logging
from logging.handlers import RotatingFileHandler
if not app.debug:
if not os.path.exists('logs'):
os.mkdir('logs')
file_handler = RotatingFileHandler('logs/app.log', maxBytes=10240, backupCount=10)
file_handler.setFormatter(logging.Formatter(
'%(asctime)s %(levelname)s: %(message)s [in %(pathname)s:%(lineno)d]'
))
file_handler.setLevel(logging.INFO)
app.logger.addHandler(file_handler)
app.logger.setLevel(logging.INFO)
app.logger.info('Flask application started')
Integrating Flask extensions
Popular extensions
Flask‑WTF – forms and CSRF protection:
pip install flask-wtf
Flask‑Login – authentication system:
pip install flask-login
Flask‑Migrate – database migrations:
pip install flask-migrate
Flask‑Mail – email sending:
pip install flask-mail
Example using Flask‑WTF
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')
@app.route("/contact", methods=["GET", "POST"])
def contact():
form = ContactForm()
if form.validate_on_submit():
# Process the form
return redirect(url_for("thank_you"))
return render_template("contact.html", form=form)
Organizing a large‑scale project
Recommended structure
project/
├── app/
│ ├── __init__.py
│ ├── models.py
│ ├── routes.py
│ ├── forms.py
│ └── utils.py
├── templates/
│ ├── base.html
│ ├── index.html
│ └── errors/
│ ├── 404.html
│ └── 500.html
├── static/
│ ├── css/
│ ├── js/
│ └── images/
├── migrations/
├── tests/
├── config.py
├── requirements.txt
└── run.py
Using Blueprint
# app/main.py
from flask import Blueprint
main = Blueprint('main', __name__)
@main.route('/')
def index():
return render_template('index.html')
@main.route('/about')
def about():
return render_template('about.html')
# app/__init__.py
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
def create_app():
app = Flask(__name__)
app.config.from_object('config')
db.init_app(app)
from app.main import main as main_blueprint
app.register_blueprint(main_blueprint)
return app
Testing Flask applications
Basic tests
import pytest
from app import create_app, db
@pytest.fixture
def app():
app = create_app()
app.config['TESTING'] = True
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///:memory:'
with app.app_context():
db.create_all()
yield app
db.drop_all()
@pytest.fixture
def client(app):
return app.test_client()
def test_home_page(client):
response = client.get('/')
assert response.status_code == 200
assert b'Welcome' in response.data
def test_login_post(client):
response = client.post('/login', data={
'username': 'testuser',
'password': 'testpass'
})
assert response.status_code == 302 # Redirect after successful login
API testing
def test_api_users_get(client):
response = client.get('/api/users')
assert response.status_code == 200
assert response.content_type == 'application/json'
def test_api_users_post(client):
response = client.post('/api/users', json={
'username': 'newuser',
'email': 'newuser@example.com'
})
assert response.status_code == 201
data = response.get_json()
assert data['message'] == 'User created'
Deploying Flask applications
Using Gunicorn
pip install gunicorn
gunicorn -w 4 -b 127.0.0.1:8000 app:app
Docker container
FROM python:3.9-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt
COPY . .
EXPOSE 5000
CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:5000", "app:app"]
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
config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}
Table of core Flask methods and functions
| Component | Description | Example usage |
|---|---|---|
Flask(__name__) |
Creates a Flask application instance | app = Flask(__name__) |
@app.route() |
Decorator for routing | @app.route('/users') |
render_template() |
Renders an HTML template | render_template('index.html', data=data) |
request.method |
HTTP request method | if request.method == 'POST': |
request.form |
Data from an HTML form | username = request.form['username'] |
request.args |
Parameters from the URL | page = request.args.get('page', 1) |
request.json |
JSON request data | data = request.json |
request.files |
Uploaded files | file = request.files['upload'] |
jsonify() |
Creates a JSON response | return jsonify({'status': 'success'}) |
redirect() |
HTTP redirect | return redirect(url_for('home')) |
url_for() |
Generates a URL by endpoint name | url_for('user_profile', id=1) |
session |
Session handling | session['user_id'] = user.id |
make_response() |
Creates a response object | resp = make_response('Hello') |
abort() |
Raises an HTTP error | abort(404) |
flash() |
Messages for the user | flash('Saved successfully') |
get_flashed_messages() |
Retrieves flashed messages | messages = get_flashed_messages() |
@app.before_request |
Executes before each request | @app.before_request |
@app.after_request |
Executes after each request | @app.after_request |
@app.errorhandler() |
Error handling | @app.errorhandler(404) |
Blueprint() |
Creates an application module | bp = Blueprint('main', __name__) |
app.register_blueprint() |
Registers a Blueprint | app.register_blueprint(bp) |
current_app |
Current application context | current_app.config['DEBUG'] |
g |
Global request context object | g.user = current_user |
Practical Flask use cases
Creating APIs for mobile applications
Flask is ideal for building RESTful APIs that serve mobile apps. Its lightweight nature and flexibility enable rapid development and scaling of API services.
Admin panels and CRM systems
By combining Flask with extensions like Flask‑Admin and Flask‑Login, you can build powerful admin dashboards and CRM solutions.
Back‑ends for chat bots and Telegram bots
Flask can serve as a webhook server to process messages from various messengers and social networks.
Real‑time monitoring and analytics
With WebSocket support via Flask‑SocketIO, you can create monitoring systems with live data updates.
Prototyping ML/AI models
Flask lets you quickly build web interfaces for machine learning and AI models, exposing them through REST APIs.
Security in Flask
CSRF protection
from flask_wtf.csrf import CSRFProtect
csrf = CSRFProtect(app)
Password hashing
from werkzeug.security import generate_password_hash, check_password_hash
password_hash = generate_password_hash('user_password')
is_valid = check_password_hash(password_hash, 'user_password')
Data validation
from wtforms.validators import DataRequired, Length, Email, ValidationError
def validate_username(self, username):
user = User.query.filter_by(username=username.data).first()
if user:
raise ValidationError('Username is already taken')
Performance optimization
Caching
from flask_caching import Cache
cache = Cache(app)
@app.route('/expensive_operation')
@cache.cached(timeout=300) # 5 minutes
def expensive_operation():
# Long‑running operation
return result
Pagination
@app.route('/posts')
def posts():
page = request.args.get('page', 1, type=int)
posts = Post.query.paginate(
page=page,
per_page=10,
error_out=False
)
return render_template('posts.html', posts=posts)
Frequently asked questions
What is Flask and what is it used for?
Flask is a lightweight Python web framework for building web applications, REST APIs, and web services. It is great for prototyping, creating micro‑services, and developing both small and large web applications.
Does Flask support databases?
Yes, Flask works with various databases through extensions. The most popular is Flask‑SQLAlchemy, which integrates SQLAlchemy ORM and supports SQLite, PostgreSQL, MySQL, and others.
Is Flask an asynchronous framework?
Flask supports async functions starting with version 2.0, but it is not a fully asynchronous framework. For full async development, consider FastAPI or Quart.
Can Flask be used for large projects?
Yes, Flask can power large projects when architected properly. Key principles include using Blueprints for modularity, organizing code wisely, applying design patterns, and leveraging appropriate extensions.
How does Flask differ from Django?
Flask is a micro‑framework with minimal structure, providing only core components. Django is a full‑featured framework with many built‑in features (ORM, admin panel, authentication system). Flask offers more flexibility; Django offers more out‑of‑the‑box functionality.
How to ensure Flask application security?
Key security measures: use CSRF protection, hash passwords, validate user input, enforce HTTPS, set proper security headers, and keep dependencies up to date.
Which Flask extensions are most useful?
Most useful extensions: Flask‑SQLAlchemy (database), Flask‑Login (authentication), Flask‑WTF (forms), Flask‑Migrate (migrations), Flask‑Mail (email), Flask‑CORS (CORS), Flask‑Caching (caching).
How to deploy a Flask app in production?
For production, use a WSGI server (Gunicorn, uWSGI) behind a reverse proxy (Nginx). Containerization with Docker and cloud platforms (Heroku, AWS, Google Cloud) are also common options.
Conclusion
Flask is a powerful and flexible tool for developing Python web applications. Its philosophy of minimalism and extensibility makes it an ideal choice for a wide range of tasks—from simple prototypes to complex enterprise systems.
Key advantages of Flask:
- Ease of learning and use
- Flexibility and extensibility
- Rich ecosystem of extensions
- Active developer community
- Excellent documentation
- Compatibility with modern technologies
Thanks to these qualities, Flask remains one of the most popular Python web frameworks and continues to evolve, adapting to modern web development requirements. Whether you are a beginner or an experienced professional, Flask provides all the tools needed to build high‑quality web applications.
The Future of AI in Mathematics and Everyday Life: How Intelligent Agents Are Already Changing the Game
Experts warned about the risks of fake charity with AI
In Russia, universal AI-agent for robots and industrial processes was developed