Macros in Flask

Outline

When rendering templates in Flask, oftentimes you have near-duplicate content copy/pasted over and over again. This does not follow DRY (don't repeat yourself) coding principles and would be better suited for a reusable function. Flask's templating structure is based upon the templating language Jinja. Jinja has a form of functions called macros.

What is a macro?

A macro is a function with the following format:

{% macro myFunction(content, class="my-content-class") %}
    <div class="{{ class }}">{{ content }}</div>
{% endmacro %}

From the example, we can see that a macro begins with the keyword macro and follows the closing structure of if and for statements. The function can take arguments and default values (see the class param). Inside of the macro, you can write any jinja code you wish including if/for/set statements allowing for rich features.

Basic Example

Let's take a simple nav bar and turn it into a reusable macro. Here is the HTML Version:

<ul>
    <li class="nav-item"><a href="/" class="nav-link">Home</a></li>
    <li class="nav-item"><a href="/blog/" class="nav-link">Blog</a></li>
    <li class="nav-item"><a href="/about/" class="nav-link">About</a></li>
    <li class="nav-item"><a href="/contact/" class="nav-link">Contact</a></li>
</ul>

Setup

We want to build a macro that will allow us to simplify the above HTML. First, what parameters will the macro take in?

  1. Display Name = name
  2. Endpoint = endpoint
  3. Optional
    • List Item Class = li_class
    • Link Class = a_class

Lastly, it would also be nice to have the macro add an active class to the link we are currently on. Alright, let's see what we have:

{% macro nav_link(name, endpoint, li_classes="", a_classes="") %} 
    {% if request.endpoint and request.endpoint.endswith(endpoint) %} 
        <li class="nav-item {{li_classes}}"><a class="nav-link active {{a_classes}}" href="{{ url_for(endpoint) }}">{{name}}</a></li> 
    {% else %} 
        <li class="nav-item {{li_classes}}"><a class="nav-link {{a_classes}}" href="{{ url_for(endpoint) }}">{{name}}</a></li> 
    {% endif %} 
{% endmacro %}

Usage

Generally, it is best practice to place macros in a specific file and import them when needed. For this example, let's say that we are placing our macros in includes/macros.html. Now in another file, we can import the nav_link macro as follows:

{% from "includes/macros.html" import nav_link with context %}

To re-build our above HTML we could do:

<ul>
    {{ nav_link('Home', 'home') }}
    {{ nav_link('Blog', 'blog') }}
    {{ nav_link('About', 'about') }}
    {{ nav_link('Contact', 'contact', a_classes="contact-link") }}
</ul>

Conclusion

You now have a basic understanding of how to create macros and use DRY principles when templating your Flask application. For this website, we built macros for the pagination setup, links, and buttons to simplify our template files and clean up our code. Now see what you can build!

Comments

Login to Add comments.