Flask Filters and Macros
Jinja2 filters transform the value of a variable before displaying it. Macros work like reusable functions inside templates — you define a block of HTML once and call it anywhere. Both tools reduce repetition and keep templates clean.
What Is a Filter
A filter applies a transformation to a variable using the pipe character |. Think of it like a water pipe with a filter attached — water (data) flows in, gets cleaned or changed, and comes out the other side in a different form.
Variable: {{ "hello world" | title }}
─────────────────────────
Input Pipe Filter
Result: "Hello World"
Built-In Jinja2 Filters
| Filter | What It Does | Example | Output |
|---|---|---|---|
upper | Converts to uppercase | {{ 'hello' | upper }} | HELLO |
lower | Converts to lowercase | {{ 'HELLO' | lower }} | hello |
title | Title case | {{ 'hello world' | title }} | Hello World |
capitalize | First letter uppercase | {{ 'alice' | capitalize }} | Alice |
length | Count items | {{ [1,2,3] | length }} | 3 |
default | Fallback if value is empty | {{ name | default('Guest') }} | Guest (if name is None) |
truncate | Shorten text with ellipsis | {{ text | truncate(50) }} | First 50 chars... |
replace | Replace substrings | {{ 'hi-there' | replace('-', ' ') }} | hi there |
safe | Render HTML without escaping | {{ html_content | safe }} | Rendered HTML |
join | Join list into a string | {{ tags | join(', ') }} | python, flask, web |
Chaining Filters
Apply multiple filters one after another. Each filter receives the output of the previous one:
{{ " hello world " | strip | title }}
{# Result: "Hello World" #}Custom Filters in Flask
Register your own filter using the @app.template_filter() decorator in Python:
@app.template_filter('currency')
def currency_filter(value):
return f'${value:,.2f}'Use it in any template:
<p>Price: {{ 1999.5 | currency }}</p>
{# Output: Price: $1,999.50 #}Another Custom Filter: Time Ago
from datetime import datetime
@app.template_filter('time_ago')
def time_ago_filter(dt):
diff = datetime.now() - dt
days = diff.days
if days == 0:
return 'Today'
elif days == 1:
return 'Yesterday'
else:
return f'{days} days ago'In template:
<p>Posted: {{ post.created_at | time_ago }}</p>
{# Output: Posted: 3 days ago #}What Is a Macro
A macro is a reusable HTML snippet with optional parameters — like a function in Python, but written in a Jinja2 template. Define a macro once, then call it multiple times throughout your templates.
The Stamp Analogy
A macro is like a rubber stamp. You carve the stamp once (define the macro), then press it as many times as you need (call the macro). Each press produces the same output, but you can change the ink color (parameters) for variation.
Defining and Using a Macro
Create a file called templates/macros.html:
{% macro input_field(name, label, type='text', placeholder='') %}
<div class="form-group">
<label for="{{ name }}">{{ label }}</label>
<input
type="{{ type }}"
id="{{ name }}"
name="{{ name }}"
placeholder="{{ placeholder }}"
>
</div>
{% endmacro %}Import and use the macro in another template:
{% from 'macros.html' import input_field %}
<form method="POST">
{{ input_field('username', 'Username', placeholder='Enter your username') }}
{{ input_field('email', 'Email', type='email', placeholder='you@example.com') }}
{{ input_field('password', 'Password', type='password') }}
<button type="submit">Register</button>
</form>Each call to input_field() generates the full <div> block with the correct label and input. Changing the macro's HTML once updates every form field everywhere.
Macro with a Default Value
Parameters can have default values, making arguments optional:
{% macro alert(message, type='info') %}
<div class="alert alert-{{ type }}">
{{ message }}
</div>
{% endmacro %}{{ alert('Profile saved!', 'success') }}
{{ alert('Something went wrong.', 'danger') }}
{{ alert('Note: This action is permanent.') }} {# uses default type='info' #}Filters vs Macros: When to Use Each
| Use Case | Tool |
|---|---|
| Transform a value (format date, uppercase text) | Filter |
| Reuse an HTML block with slight variations | Macro |
| Custom Python logic on template values | Custom filter registered in Python |
| Repeated form inputs or UI components | Macro |
Summary
Filters transform variable values using the pipe character. Built-in filters handle common tasks like formatting, truncating, and joining. Custom filters extend Jinja2 with Python logic. Macros create reusable HTML blocks with parameters, eliminating copy-paste repetition in your templates. Use filters for data transformation and macros for reusable HTML structures.
