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()