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

FilterWhat It DoesExampleOutput
upperConverts to uppercase{{ 'hello' | upper }}HELLO
lowerConverts to lowercase{{ 'HELLO' | lower }}hello
titleTitle case{{ 'hello world' | title }}Hello World
capitalizeFirst letter uppercase{{ 'alice' | capitalize }}Alice
lengthCount items{{ [1,2,3] | length }}3
defaultFallback if value is empty{{ name | default('Guest') }}Guest (if name is None)
truncateShorten text with ellipsis{{ text | truncate(50) }}First 50 chars...
replaceReplace substrings{{ 'hi-there' | replace('-', ' ') }}hi there
safeRender HTML without escaping{{ html_content | safe }}Rendered HTML
joinJoin 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 CaseTool
Transform a value (format date, uppercase text)Filter
Reuse an HTML block with slight variationsMacro
Custom Python logic on template valuesCustom filter registered in Python
Repeated form inputs or UI componentsMacro

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.

Leave a Comment

Your email address will not be published. Required fields are marked *