Skip to main content

Basics

Installation

pip install Flask

Basic Application Structure

from flask import Flask

app = Flask(__name__)

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

@app.route('/user/<name>')
def user(name):
return f'Hello, {name}!'

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

Running the Application

Development Server

# Set environment variables
export FLASK_APP=app.py
export FLASK_ENV=development

# Run the application
flask run

# Or run directly
python app.py

# Run on specific host and port
flask run --host=0.0.0.0 --port=5000

Application Factory Pattern

from flask import Flask

def create_app(config_name='default'):
app = Flask(__name__)
app.config.from_object(config[config_name])

from .main import main as main_blueprint
app.register_blueprint(main_blueprint)

return app

Routing

Basic Routes

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

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

@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 {post_id}'

HTTP Methods

from flask import request

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

@app.route('/submit', methods=['POST'])
def submit():
return 'Form submitted'

@app.route('/api/data', methods=['GET', 'POST', 'PUT', 'DELETE'])
def api_data():
if request.method == 'GET':
return get_data()
elif request.method == 'POST':
return create_data()
elif request.method == 'PUT':
return update_data()
elif request.method == 'DELETE':
return delete_data()

URL Variables

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

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

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

@app.route('/user/<uuid:user_id>')
def show_user_by_id(user_id):
return f'User ID: {user_id}'

URL Building

from flask import url_for

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

@app.route('/login')
def login():
return 'login'

@app.route('/user/<username>')
def profile(username):
return f'{username}\'s profile'

with app.test_request_context():
print(url_for('index')) # /
print(url_for('login')) # /login
print(url_for('profile', username='John')) # /user/John

Configuration

Configuration Variables

class Config:
SECRET_KEY = 'your-secret-key-here'
DATABASE_URI = 'sqlite:///app.db'
MAIL_SERVER = 'smtp.gmail.com'
MAIL_PORT = 587
MAIL_USE_TLS = True
MAIL_USERNAME = 'your-email@gmail.com'
MAIL_PASSWORD = 'your-password'

app.config.from_object(Config)

# Or load from environment
import os
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY')

Environment-based Configuration

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
SQLALCHEMY_DATABASE_URI = 'sqlite:///dev.db'

class ProductionConfig(Config):
DEBUG = False
SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL')

config = {
'development': DevelopmentConfig,
'production': ProductionConfig,
'default': DevelopmentConfig
}

Request Context

Request Object

from flask import request

@app.route('/method')
def method():
return request.method

@app.route('/headers')
def headers():
return dict(request.headers)

@app.route('/user-agent')
def user_agent():
return request.headers.get('User-Agent')

Application Context

from flask import g, current_app

@app.before_request
def before_request():
g.user = get_current_user()

@app.route('/user')
def user():
return g.user.username if g.user else 'Anonymous'

Error Handling

Error Handlers

@app.errorhandler(404)
def not_found(error):
return 'Page not found', 404

@app.errorhandler(500)
def internal_error(error):
return 'Internal server error', 500

@app.errorhandler(Exception)
def handle_exception(e):
return f'An error occurred: {str(e)}', 500

Custom Exceptions

class ValidationError(Exception):
pass

@app.errorhandler(ValidationError)
def handle_validation_error(e):
return str(e), 400

@app.route('/validate')
def validate():
if not request.args.get('data'):
raise ValidationError('Data is required')
return 'Valid data'

Logging

Basic Logging

import logging
from logging.handlers import RotatingFileHandler

if not app.debug:
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('Application startup')

@app.route('/log')
def log_example():
app.logger.info('Info message')
app.logger.warning('Warning message')
app.logger.error('Error message')
return 'Check logs'

Static Files

Serving Static Files

# Static files go in 'static' folder
# CSS: static/css/style.css
# JS: static/js/app.js
# Images: static/images/logo.png

# In templates:
# <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">

Custom Static Folder

app = Flask(__name__, static_folder='assets', static_url_path='/assets')

Testing

Test Client

import unittest

class FlaskTestCase(unittest.TestCase):
def setUp(self):
self.app = app.test_client()
self.app.testing = True

def test_index(self):
result = self.app.get('/')
self.assertEqual(result.status_code, 200)
self.assertIn(b'Hello, World!', result.data)

def test_login(self):
result = self.app.post('/login', data={
'username': 'test',
'password': 'test'
})
self.assertEqual(result.status_code, 200)

if __name__ == '__main__':
unittest.main()