Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Inclusion Macros

00:00 In the previous lesson, I showed you a whole bunch of filters. In this lesson, you’ll learn how to write Jinja2 macros.

00:09 A macro is like an {% include %} that can take arguments. In fact, in the Django templating language, which is similar to Jinja2, it just adds this functionality to the {% include %} tag. Macros are like functions in Python, in that they encapsulate a reusable chunk which can be parameterized.

00:29 This is useful for creating subtemplates, similar to the nav one you saw, but allowing you to include conditional behavior based on arguments as well.

00:39 Before showing you macros, brief detour. When Flask renders a template, it includes a value in the context dictionary called request that contains information about the HTTP request that hit the page.

00:53 This object contains the page’s URL as well as any query parameters in the request. Let’s go write a macro using this feature.

01:05 Okay, here’s my new view. It calls the tara.html template.

01:15 And before looking at tara.html, first let’s look at macros.html. This file defines the light_or_dark_mode() macro, which allows visitors to your site to turn on dark mode if they prefer. To define a macro, you use the {% macro %} tag, and then you write the name of it and any arguments it takes in parentheses.

01:36 This macro takes the name of an element and will apply light or dark styling to that element depending on a query parameter in the URL. As I mentioned before, the request object is sent in by Flask.

01:50 Its .args attribute contains any query parameters. Here, I’m checking if there was a parameter named mode and if it’s set to "dark".

02:01 If it is, I add a <style> tag to the page, adding CSS to the element whose name was passed into the macro. Realistically, this is always going to be the body tag, but if I had hard-coded that, you wouldn’t be able to see the use of a macro’s arguments. Just on top of the <style> trunk here, I have a link to the same page that the user is on, but without any query parameters in the URL. I get the current URL from the request object’s .path attribute, and then here I’m doing the opposite. In the {% else %} clause, I take the current URL and stick the dark mode parms on the end.

02:42 Now anywhere this macro is used, you get both this style-change functionality and a link to swap to the other style. Okay, let me show you how this gets used.

02:56 And this is tara.html. The {% import %} tag is how you get at the macros defined in a template. The as argument here defines a name that groups all the macros, kind of like importing a Python module.

03:12 And here in the footer of the page, I use the actual macro, calling it just like other functions you’ve seen in Jinja2, the only difference here being the namespace.

03:21 My macros that got defined above this <footer> tag will contain the code defined in the light_or_dark_mode() macro that I just showed you.

03:32 Okay, let’s go look at this in the browser.

03:42 Because I started with no arguments, it defaults to light mode. The link here at the bottom contains the same URL, but with the dark mode parameters turned on.

03:53 Let me click it, and there you go. Angry Willow it is. You’ve gone all dark.

04:03 Let’s look at another macro. I’ve added a new view as well as a data class to app.py. If you haven’t played with data classes before, they’re a way of doing a dictionary-like thing inside of a class, with the added benefit of type restrictions. To declare a data class, you use a special decorator on a class definition.

04:24 Here, I’m importing that decorator, and then I use it to create the Swimmer class. Inside of Swimmer, I spec out two attributes, .name and .speed, which are a string and integer, respectively.

04:40 Inside the swim view, I have some swimmers, which I populate using the Swimmer object. Each of these data class instances has a name and a speed score.

04:52 Don’t ask me what 7 means as a speed. Miles per hour? Kilometers per second? Mach? Doesn’t really matter to me. Just 7. Okay,

05:05 and here’s my new macro. Similar to before, I declare it using the macro tag, and this time I’m calling it the swimmer_item(). It takes a swimmer as an argument.

05:17 Inside the macro, I output some HTML data. Class attributes can be accessed through dot notation (.), so this is how you get the name and speed out of the item passed in.

05:32 And here’s the swimmers page. Like before, I import macros.html as my macros, and then inside of my for loop, I call the macro.

05:44 There isn’t anything here much different from the dark mode idea, but this is a common use case. Say you have a row in a table with some complex formatting.

05:53 You can create a macro that renders the row, passing in the values for the columns in the row, and then repeatedly use it with a for loop. All of this reduces the amount of HTML in this file, encapsulating the other code in another file and making it all more readable.

06:11 Just to throw something new at you, here I’m using the {% set %} tag to create a value called best. The map filter creates an iterable by processing an iterable. In this case, it goes through all the swimmers and puts the speed value for each into a new iterable. That new iterable then gets filtered through max.

06:32 This allows me to find the largest speed and then render that value in the line below this. Let’s go take a dip in the pool.

06:50 And there you go. The macro got called four times, once for each member of the Razorbacks swim team. And here at the bottom is the max speed of 8.

06:59 Seeing as mach is related to the speed of sound, is mach eight in the water eight times the speed of sound in the air or eight times the speed of sound in the water? This is the kind of thing that keeps me up at night.

07:15 And that’s it, boys and girls. You’re now familiar with Jinja2 templating and a smattering of Flask. Last up, I’ll summarize the course and point you at some places for further investigation.

Become a Member to join the conversation.