📱

Get Our Mobile App

Take your business learning on the go!

Download on the App StoreGet it on Google Play

Rewst 103: Jinja Essentials for Workflow Automation

Rewst26:27

Transcription

Hello and welcome. In this video, we're going to be talking about Jinja and the essentials of Jinja. Let's go ahead and get started. And as always, thank you for watching.

So, as we progress through the video, we're going to be talking about what is Jinja, some of the basic syntax, what we can do with Jinja using the Jinja live editor, and a very important concept called list comprehension.

So, what is Jinja? Jinja is a templating language or a programming language that we usually use to create or modify some sort of data. That data can come in a number of different formats. In the format that we generally see it as is JSON. As with many programming languages, a lot of the features and functionality that we would expect are also here in Jinja, things like loops, conditional statements, and creating and modifying variables. Here in the Roost world, we are using Jinja to do just that: modify and process information.

When we're using Jinja, a lot of what we've seen already with Jinja is with braces, and specifically curly braces. So now we can finally put together what are those two curly braces. So, when we're using two curly braces, this is letting us know that we are outputting a specific value. So, in our example of Roost 102, we are outputting the value of things like the user ID, the group ID, and the action variable.

A curly brace with a percent sign is denoting a block of code that we want to run. Generally, we're using this syntax when doing things like if-else statements or for loops.

And finally, the last syntax I want to highlight is the curly brace with the pound sign or the hashtag. This is denoting comments.

Let's talk a little bit about JSON files. A JSON file is used to represent data, and it's done in a way where we can easily read it. Let's take a look and see an example really quick. The way JSON files work is through what we call key-value pairs. So, on the left-hand side are our keys, and then the right-hand side is the value that's assigned to a key. So, very similar to variables and assigning values to variables. So, some of the examples that we have here are things like a name, which is the key, and then the value, which is Han Solo. We have age, and the value is 4, and so on and so forth. You'll see that in the JSON file, there are a number of different format types that it supports, things like strings, integers, and lists.

As we discussed in Roost 102, we have variables that live in this place called the context, and we refer to those as context variables. Those variables are created within the Jinja world, and we can also create variables in a section of our workflows called data aliases. So, whether we're calling them variables, context variables, or data aliases, these are three different terms referring to the same thing. In this slide here, we're just highlighting that we can create data aliases and assign values to them, and this is all done behind the scenes using Jinja.

So, let's highlight some of the things we can do in Jinja. As with most programming languages, we can have if-else statements. So, we can check a specific condition to see if it is or isn't true. So, in this first example, we're checking to see if the user is logged in. If the user is logged in, then we will perform something. In this case, we are outputting the sentence "Welcome" followed by the output of the username variable. So, we see the two curly brackets here; this is letting us know that we are outputting the value of the variable username. We hit the next line on line number three. Otherwise, or if the condition is not true on line one, then we're going to execute whatever's after the else. In this case, we're going to be outputting the statement "Please log in to continue." And then in Jinja syntax, we're going to need to end the if-else statement on line five.

On the right-hand side here, here's another example of using an if-else statement using a feature called else if. So, we can check multiple conditions using this type of feature. So, we're going to check if X is equal to one. We're going to print out that sentence on line two. Else if X is equal to two, we'll print out the sentence on line four. And then the final else is catching every other thing. So, if not the first, so if X is not equal to one and if X is not equal to two, everything else, we're going to be printing line six. So, highlighting some of the things we can do in the Jinja world, specifically if-else statements.

Let's talk about filters. Filters are pre-configured algorithms or functionality that we can use without having to implement any sort of logic or code. So, commonly used filters such as capitalize, upper, and lower allow us to perform these commonly used tasks without having to implement anything on our end. All we need to do is use the filter. And the way we use the filter is taking the output of something and passing it or sending it to the filter. And the way that we do that is with a character called the pipe character. So, some of the examples down here at the bottom, we have a specific text variable. We are outputting the value of the text variable with those two curly brackets into the filter called truncate. Truncate is going to shorten or truncate the length of the text to 20 characters. The other example here is we're going to take the output of a username or send it to the filter called capitalize using the pipe character, and it will capitalize the first letter of the string. And the last example shows that we can send the output of a variable through multiple filters. So, the user's email will be sent through the lower filter, which will lowercase the email, and then it will replace the "@" sign with the word "at" in the lowercase email. So, filters are beneficial because it allows us to implement these commonly used tasks without having to program it ourselves. We've also implemented some filters in the Roost world, and here are a list of a couple of those.

And finally, we have this thing called list comprehension. List comprehension is a special syntax that's used to create lists. When we are in our demo environment, I'll speak more about list comprehension, but for now, just remember that list comprehension is a special syntax that's used to create a list based off of other lists and conditions that we set.

Next up, we're looking at for loops. Generally speaking, when we're using for loops in Jinja, it's a way for us to go through each item of a list. So, the way that it works is we designate what I like to call a pointer, and what the pointer will do is exactly what the name says: it will point at each item of a list. So, starting with our line one at the very top, we have a pointer named "thing," and this pointer will point at each item of our list of "things." And as it points at each item, it will output the value of the thing that the pointer is pointing at. So, if we have a list of three items, the "thing" pointer will point at each of the three items, and for each time that it does, it will output the value of the thing.

The next example down here is showing how we can add conditions to our for loop. So, same parts from the beginning, we have a pointer called "thing" that will point at each item of our list. We're then going to do a check and say, "If the thing that the pointer is pointing at does not equal 'bad stuff'," then we will output the value of the thing that the pointer is pointing at. Then it will output the value of the thing.

As a note, the editor that we're using throughout Roost is known as The Monaco editor, and it is the same editor that's used in VS Code. So, if you're familiar with many of the shortcuts in VS Code, you can also use it within the editor in Roost.

We're going to dive into our example shortly, but to give a preview of what it is, we're going to have some data presented to us in JSON. And this data will have a menu. We'll have a menu of what's for lunch. We'll go through that menu and execute some Jinja statements to answer some of the questions here in the description of this video, as well as on the page that this video is on. We'll be using this URL. So, go ahead and click on the URL, and I'll meet you over in our instance of Roost.

After clicking the link, it brings us over to our Jinja live editor. We see there are some pre-populated comments within the editor itself, and then if we expand out the context, there's also some data in here. I'll collapse some of the things within our context so we can easily see what's inside. So, the first thing I'll highlight is there are two variables within our context: we have "days" and then we have "week." Here, the "week" is a simple string, and then "days" is a list. We know it's a list based off of the square brace there. Expanding out "days" will reveal all of the days, and then within each day, it'll have things like the lunch, the drinks, the entrees, etc. And then you can take a little bit of time to look through. Each day has a number of attributes to it. So, within our "days" variable, we have a number of items. So, I'll be referring to each day within our "days" list as an item. So, each of our items has a number of attributes that we can access.

Now, let's head down to our Jinja live editor and uncomment some of these commands and see what they do. As a heads-up, I'm going to be using the keyboard shortcut Ctrl+Enter or Command+Return if you are on a Mac. That will render or execute our Jinja code. You can also click on the render button down at the bottom right. I'll also be uncommenting using Ctrl followed by forward slash. So, let's go ahead and start with our first line here. So, two curly brackets lets us know we're outputting the value of something, and the thing that we're outputting will be the entire context. So, rendering this command like so will show us the entire context. Context comes to us as "result," and then the result of the context is what we see within the context up here in the drop-down. Within the context, we can access a couple of different things, such as the "week" variable, and we'll see that it renders the value of the "week" variable that lines up exactly with what we see within the context.

What we can do next is send our variables through a filter. So, taking the "days" variable, we can then send the output of "days" through a filter called "length." This will give us the number of items within our list that represents the number of days within our "days" variable. So, taking the output of `ctx.days` and sending it or piping it to our filter called "length." So, that takes care of a couple of things here, highlighting that the double curlies output the value of a variable, we can access the context using `ctx`, and then access the variables using dot followed by the variable name.

Let's see some other things that we can do with Jinja. I'll start here at line 17 and uncomment down to line 19. Starting on line 17, we see a for loop, and as we discussed in the slides, a for loop allows us to go through each item of a list. The way that we do that is by giving a name to what I like to call a pointer, and the pointer will point at each item of the list. As we do, there are a number of things that you can do with that. In this example here on line 18, our pointer is called "weekday," and as it points at an item, we can access the attributes of the item. So, in this situation, we're accessing the attribute of "day" followed by "lunch" and "dessert" over in this change statement here. So, if I go back into the context, you'll see that within our item, we have the "day" attribute, this example is Friday, and then the "lunch" attribute also has some attributes of its own. So, "lunch" has the attribute of "dessert" right here. So, the pointer points at an item and allows us to access the attributes and sub-attributes of the item that it's pointing at. So, let's go ahead and run this code and see what happens. So, you'll see it points at each item within our list called "days." As it does, we will be accessing the "date" attribute and then the "lunch" and "dessert" attribute and printing those out as sentences that we see here on line 18 and the result over here on the right-hand side. So, for loops allow us to go through each item of a list, and as we do, we can access the attributes that the pointer is pointing at to do something.

The next thing we're going to be highlighting is list comprehension. So, as a recap, list comprehension is a special syntax that we use to create lists based off of other lists and conditions. If you're familiar with list comprehension in the Python world, this is the same thing here in the Jinja Roost world, but if not, that's okay. Let's go ahead and talk through what this comprehension is and how the syntax works. So, the syntax in list comprehension will have at least two lines, but sometimes it'll have three lines. So, I'll start off here and I will start a new list comprehension just for example to highlight what those three lines are. So, the first line I like to call the "output." So, when we're creating a new list, what is the new list of items that is going to be the output? The second line I like to call "construction." This is how are we building our new list, or in other words, which existing lists are we using to build our new list? So, I like to call this "construction." And then the last line I like to call "condition" is the conditions that we use to pick and choose the different items of the list that we are building our new list off of. So, conditions: if this, add it to our new list; if not, this, exclude it from our list. Those type of conditions. So, generally, list comprehension follows this type of syntax: we'll output a new list, we're going to build that new list based off an existing list, and then we're going to use filters or conditions to pick and choose the items of an existing list to add to our new list.

So, let's go ahead and see this in action. So, I'll start by uncommenting line 22 to line 27 using my keyboard shortcut Ctrl+/ or Command+/. And the first line here is the output. The second line here is our construction. I generally like to start with the second line; it makes it easier to explain. So, the second line is what are we building our new list from? The construction part. So, we have a pointer called "weekday," and it's going to be pointing at each item of the list `ctx.days`. Since we don't have a third line, there are no conditions to filter which items we're picking and choosing. In this situation, we're going to be picking all of the items in the `ctx.days` list. The output of the new list will be what we see here: this sentence, "The dessert on the day attribute of what the pointer is pointing at," followed by the "lunch dessert" attribute of the item that the pointer is pointing at, to give us the descendants, "the dessert on a specific day is the dessert." So, if we run this, this will look very similar to what we saw in the previous example, but using list comprehension.

I'll go ahead and comment this away and then we'll see another example of list comprehension. So, uncommenting line 34 to 39. Same idea on the second part of our list comprehension, we're building our new list off of the list `ctx.days`, and as we point at each item, the output of our new list is going to be the "lunch" and then the "sides" attribute. So, we can see as it points at each item, it will access the "lunch" followed by the "sides" attribute, and let's see what this looks like. You'll then see it's giving us a result of the sides for each day, and you'll notice that the sides is represented as a list, as you can see in my example here on line 98.

So, one thing we can do is reduce our list of lists. So, we can take all of the results of our lists and put them together as one list, and we can use a filter to do that. So, at the end of my list comprehension, I can take the output of my new list and pass it to a filter called "flatten." When I run this, what it will do is take all of the items out of the lists and consolidate it or flatten it into one list. We can then show some other examples here of taking the results of one filter and sending it to another. So, maybe I want to sort the list in alphabetical order, and we have the list in alphabetical order. And then you'll notice that there's "sweet potato fries" twice. So, maybe I only want a list of the unique sides. So, I don't need to see "sweet potato fries" twice; I just need to know that it is a side. So, I can pass the results to yet another filter, and we can use a filter called "unique," and it'll show me the unique values within my list. So, some examples here of using filters. And again, if you're curious as to what filters are available to you, there'll be a link to the documentation in the description or on the page that this video is on.

Let's go ahead and comment these, and let's see an example of using list comprehension with a condition. So, we'll go down here to line 63 and we will uncomment this, and this is where we'll see the three-line structure I was talking about earlier: so, output, construction, condition. So, starting on the second line, this is following the same part as we've seen before: building a new list based off of our list `ctx.days`. We now have a condition. What we'll be checking to see is, as the "weekday" pointer points at each item of the list, we'll see if the "lunch.drink" attribute is equal to the string or the value "milk." So, we'll go through each item, we'll look at the drink, and see, is it equal to "milk"? If it is equal to "milk," we will add it to the list. If it is not equal to "milk," then we will exclude the item from the list. And in this case, each item that we're adding to the list, we will be outputting the "date" attribute. Let's see what this looks like. So, it will go through each item, and if it fulfills our condition, that item will be added to our list. And the way that we have our output set up, we'll be outputting the "date" attribute. And in this situation, we see that Monday is the only day that shows up.

But here in my example, you'll see that one of the drinks here is "chocolate milk." It's technically milk, but one of the issues that we have is that we are looking for the literal value "milk." Is the "drink" attribute equal to "milk"? So, to accommodate "chocolate milk," what we can do is change the way we're setting up our condition. So, rather than looking for a literal value "milk," we can just look for the word "milk" if "milk" is anywhere within the "drink" attribute. And we can switch that up like this. So, we can search for "milk" like this, as a capital, and if it is in the `weekday.lunch.drink` attribute, and if I search like this, we'll have Monday and Friday show up. But maybe the person who's setting up this menu might not capitalize "milk." We're again looking for a literal value of "milk" as uppercase, and maybe it might come out as lowercase, maybe someone might use uppercase. So, to try to account for some of these situations, we can use a filter to help us out with this. So, we can pass it to the filter called "lower," and instead of looking for a capital "milk," we can look for a lowercase "milk." So, the pointer will be pointing at "lunch" followed by "drink," and then it will lowercase the value of the drink. So, "chocolate milk" will be lowercase "c," lowercase "m," and then we're going to be looking for that lowercase "m" "milk" to again account for any sort of oddities, and we'll see that the result is the same. So, very good.

And the last thing we're going to be looking at is creating or setting variables in Jinja itself. So, starting on line 81, we are setting a variable called "milky_days," and the value of "milky_days" is going to be a list. And based off of our syntax, we're using list comprehension to create our new list. Starting on the second line, this is the same thing we've seen again and again: creating a new list based off of our list called `ctx.days` with our pointer called "weekday." And here in the condition, as our pointer points at the `lunch.drink` attribute, we're going to pass that over to our "lower" filter to lowercase the value of that attribute. We're then going to check to see if the word "milk" is in that lowercased value, the same thing we did previously. And then from here, our output is just going to be our pointer "weekday."

On line 87, we're going to have a for loop that will go through each item of the list that we just created, "milky_days," using the same pointer name, "weekday." We will have a sentence here that lets us know which day we need to bring a different drink because they're going to be serving some sort of milky drink. So, let's go ahead and run this and see how it works. So, our "milky_days" is going to contain two objects: it's going to contain our object for Monday and then our object for Friday. We have these two objects, and we're able to access their attributes using the "weekday" pointer. In line 87 for loop, we're going to access the "date" attribute as well as the "lunch.time" attribute and then the "lunch.drink" attribute. And by doing so, we're able to create more meaningful messages letting us know we should bring our own drink to lunch at this time on this day because they're serving milk.

That wraps it up for our exercise here in Roost 103. I want to thank you again for watching, and I'll see you in the next video.