Difficulty: Beginner
Variable rules allow you to capture parts of a URL and pass them as arguments to your view function. This is how Flask handles dynamic URLs like user profiles, blog posts, and API resources where the URL contains an identifier.
Variable sections in URL rules are marked with angle brackets: <variable_name>. When Flask matches a URL, it extracts the value and passes it to the view function as a keyword argument. By default, variables are captured as strings.
Flask provides built-in converters that validate and convert URL variables to specific types. You use them with the syntax <converter:variable_name>. The built-in converters are:
- string (default): Accepts any text without slashes. This is used if no converter is specified. - int: Accepts positive integers. The value is passed to the function as a Python int. - float: Accepts positive floating-point numbers. Passed as a Python float. - path: Like string but also accepts slashes. Useful for file paths. - uuid: Accepts UUID strings in the format xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. - any: Matches one of a given set of strings. Useful for selecting from a fixed list.
The int and float converters are particularly useful because they handle type validation for you. If someone visits '/user/abc' on a route defined as '/user/<int:id>', Flask returns a 404 instead of passing 'abc' to your function and letting it crash when you try to use it as a number.
You can have multiple variables in a single URL rule. For example, '/api/<version>/users/<int:user_id>/posts/<int:post_id>' captures three variables. Each variable becomes a keyword argument to the view function, so the function must accept all of them.
Flask also supports custom converters if the built-in ones do not meet your needs. You create a class that inherits from werkzeug.routing.BaseConverter, define the to_python() method (converts the URL string to a Python value) and the to_url() method (converts a Python value back to a URL string for url_for). Then you register it with app.url_map.converters.
The path converter deserves special attention. Normally, URL variables do not capture slashes, so '/files/<filename>' would match '/files/report.pdf' but not '/files/docs/report.pdf'. The path converter matches slashes too, so '/files/<path:filepath>' matches '/files/docs/2024/report.pdf' with filepath = 'docs/2024/report.pdf'.
from flask import Flask
app = Flask(__name__)
@app.route('/user/<username>')
def user_profile(username):
return f'Profile page of {username}'
@app.route('/post/<int:post_id>')
def show_post(post_id):
return f'Post #{post_id} (type: {type(post_id).__name__})'
@app.route('/price/<float:amount>')
def show_price(amount):
return f'Price: ${amount:.2f}'
Without a converter, variables are strings. The int converter ensures post_id is an integer (and returns 404 for non-integers). The float converter captures decimal numbers.
from flask import Flask
app = Flask(__name__)
@app.route('/files/<path:filepath>')
def serve_file(filepath):
return f'Serving file: {filepath}'
@app.route('/item/<uuid:item_id>')
def get_item(item_id):
return f'Item ID: {item_id} (type: {type(item_id).__name__})'
# The 'any' converter matches from a fixed set
@app.route('/lang/<any(en, fr, de, es):language>')
def set_language(language):
return f'Language set to: {language}'
The path converter captures slashes, so it can match nested paths. The uuid converter validates UUID format and returns a Python UUID object. The any converter restricts values to a predefined set.
from flask import Flask
app = Flask(__name__)
@app.route('/api/<version>/users/<int:user_id>')
def get_user(version, user_id):
return {
'api_version': version,
'user_id': user_id,
'user': f'User {user_id}'
}
@app.route('/blog/<int:year>/<int:month>/<slug>')
def blog_post(year, month, slug):
return f'Blog: {year}/{month:02d}/{slug}'
You can combine multiple variable rules in a single URL pattern. Each variable becomes a parameter of the view function. The function signature must include all variables defined in the URL rule.
from flask import Flask
from werkzeug.routing import BaseConverter
class ListConverter(BaseConverter):
"""Matches comma-separated values in URL."""
def to_python(self, value):
return value.split(',')
def to_url(self, values):
return ','.join(values)
app = Flask(__name__)
app.url_map.converters['list'] = ListConverter
@app.route('/tags/<list:tags>')
def filter_by_tags(tags):
return {'tags': tags, 'count': len(tags)}
# /tags/python,flask,web -> {"tags":["python","flask","web"],"count":3}
Custom converters extend BaseConverter. to_python() converts the URL segment to a Python object. to_url() converts back for url_for(). Register the converter on app.url_map.converters.
Variable Rules, Type Converters, string, int, float, path, uuid