python
38 lines · 6 steps
Custom URL converters in Flask
A custom slug converter validates and normalizes URL segments before your view functions ever run.
Explained by
highlit
1from werkzeug.routing import BaseConverter, ValidationError
2from flask import Flask, jsonify, abort
3
4
5class SlugConverter(BaseConverter):
6 regex = r"[a-z0-9]+(?:-[a-z0-9]+)*"
7
8 def to_python(self, value):
9 if len(value) > 200:
10 raise ValidationError()
11 return value
12
13 def to_url(self, value):
14 slug = value.strip().lower().replace(" ", "-")
15 return super().to_url(slug)
16
17
18app = Flask(__name__)
19app.url_map.converters["slug"] = SlugConverter
20
21
22@app.route("/articles/<slug:slug>")
23def show_article(slug):
24 article = Article.query.filter_by(slug=slug).first()
25 if article is None:
26 abort(404)
27 return jsonify(article.to_dict())
28
29
30@app.route("/categories/<slug:category>/<slug:slug>")
31def show_in_category(category, slug):
32 article = (
33 Article.query
34 .join(Category)
35 .filter(Category.slug == category, Article.slug == slug)
36 .first_or_404()
37 )
38 return jsonify(article.to_dict())
01 / 01
STEP 01
‹ swipe to step through ›
Walkthrough
Space play
←→ step
click any line
Three takeaways
- 1A converter's regex filters requests at the routing layer, so bad URLs never reach your view.
- 2to_python and to_url let you validate incoming segments and normalize outgoing ones symmetrically.
- 3Registering a converter by name makes it reusable across every route as <name:variable>.
Related explainers
python
from fastapi import FastAPI, WebSocket, WebSocketDisconnect app = FastAPI()
Building a WebSocket chat with FastAPI
websockets
broadcast
connection-management
Intermediate
9 steps
php
<?php namespace App\Services\Checkout;
Validating coupons with Laravel's Pipeline
pipeline
chain of responsibility
transactions
Intermediate
7 steps
ruby
class UserAgentParser BROWSERS = [ [/Edg\/([\d.]+)/, "Edge"], [/OPR\/([\d.]+)/, "Opera"],
Parsing user-agent strings in Ruby
regex
pattern-matching
lookup-tables
Intermediate
8 steps
python
import time import uuid from django.utils.deprecation import MiddlewareMixin
Attaching per-request context in Django
middleware
request lifecycle
multi-tenancy
Intermediate
7 steps
php
<?php namespace App\Services;
How a password strength validator works in PHP
validation
regular-expressions
data-driven
Intermediate
8 steps
python
import random from typing import Iterator, List
How reservoir sampling picks k items
reservoir-sampling
streaming
randomness
Intermediate
5 steps
Share this explainer
Here's the card — post it anywhere.
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code
Embed this explainer
Drop the interactive walkthrough into a blog or docs. Views never cost a credit.
<iframe src="https://highlit.co/explainers/custom-url-converters-in-flask-explained-python-f05b/embed?autoplay=1" width="100%" height="520" loading="lazy" style="border:0"></iframe>
Autoplay is on by default — add ?autoplay=0 to start paused.