Introduction: Why display tables on the web
Hi guys and welcome back. Presenting tables of data on the web is such a popular thing to do that I felt like I had to show you how I normally do it using Flask and Jinja and HTML. In this video let's take a look at how we can use Flask to easily present tables of data like in the way you see on the right side of my screen right now. Let's get started.
Overview and demo of dynamic headings and data
In this video we're going to be working with this table of data. We're going to have a table where the headings and the data are defined separately because often when we're working with data using Flask apps it's dynamic data. So let me show you what it looks like if I change the headings and the data as well. So here I've gone into my Flask app — I know you can't see it at the moment, I'll show you what it looks like in just a moment — and changed the data and the headings for my table. I've used Jinja2 to automatically draw my table based on the data I've given it, so it's really easy to modify these tables only with a couple of small lines of code changes in Python. So let's get started with this video and see how we can do that.
Set up Flask app and create a basic HTML table
What I'm going to do first of all is I'm going to create a virtual environment which I've already done down here and install Flask init and then I'm just going to go and type flask run. Whenever we type flask run that's going to start our Flask app. Now if I refresh the page here we're going to get an error; that's because at the moment in my project here I don't have any templates to display any HTML. So what we're going to do is create a templates folder and then create here table.html. So now we've got a Flask app and all it does is it defines an endpoint that when accessed returns the render template of table.html. What that's going to do is it's going to go into this HTML file, it's going to evaluate any Jinja code that is in it, it's going to turn it all into HTML and it's going to send the HTML to the user. So if we put here some HTML code, for example 'hello world', then when we refresh this page we get hello world. So what we want to do here is display a table of data. First of all let me hide away these consoles there and focus on the HTML that we're writing. In order to create a table using HTML we're going to use the table element, so that is table just like that. So now we have a table element here which is empty and we're going to populate it with rows of data. So we're going to use the tr element for the first row and in here we're going to put a th element for a table header cell and here we're going to put something like, for example, 'Name'. Then in a different row we're going to create another row of data like that and we're going to populate it with td elements for table data elements and here we're going to put, for example, 'Rolf Smith'. So if we restart the app and refresh the page you see that now we get this table of data with only one header, the Name, and one row of data which contains the person's name. We want to also display the people's roles and salaries, so what we have to do is go ahead and add a couple more headers, another one for the Role and another one for the Salary, and then of course a couple more rows each one with a couple more table data elements. So we're going to do Rob Smith is a software engineer and his salary let's say is something like 42,000. Okay, then we'll actually do the same thing for these other table data elements but we'll change the names. Okay, so I've gone ahead and changed the names and their salaries and now when we refresh the page we get the default styled HTML table with the styles the default for my browser. We're going to change these styles in just a moment.
Passing data from Flask to Jinja2 and rendering loops
Every time we access the endpoint here we're returning the table.html and render_template is going to evaluate any Jinja2 code and is going to convert it to HTML before sending the HTML to the user. At the moment we don't have any Jinja2 code in here. The Jinja2 code is used to take some data and use it to create HTML code. The data has to come from our Flask app, so we're going to extract the table data into our Flask app and how we're going to do that is by using a couple of tuples. So I'm going to have a tuple of headings, the headings of the table, and a tuple of tuples where this is a tuple containing one tuple of data for each row. So you can see here we've got Rolf, software engineer, 42,000 and so forth for every other person. Now when we return render_template we have to pass the template our data so that it can then work with it. We're going to do headings equal headings and data equal data. What this does is it creates a variable 'headings' inside our template for Jinja2 to use and the value of that variable is the headings variable. Notice that we can call this variable whatever we want. We could put 'table_headings' here if we wanted and then the template would use table_headings as its variable, but I want to keep it as headings so that they match what we've got here in Python, and the same for the data variable in our template has the value of our data variable in Python. So now we can go into our template and use Jinja2 to create this HTML table instead of hard coding everything in here. So what we'll do is for every header cell we're going to use a for loop: 'for header in headings' — we're going to use a for loop in here and for each iteration of this for loop we're going to draw one header cell that contains the header information just like that. So this behaves very much like a Python for loop, but every time we go through the for loop we're actually adding an element to the HTML. Similarly for our rows of data we're going to first of all iterate over our data, so we'll do 'for row in data' and that is going to give us a for loop that goes through each tuple in our data. So the first row will be this tuple, the second row will be this tuple and so on, and then what we'll do inside this for loop is we're going to have another for loop which has 'for cell in row' so then we're going to be able to use this inner for loop to access every individual cell in the tuple. Notice though that each row has a tr element and every cell has a td element, so we do need the tr element to be out here surrounding this for loop and we need the td elements to be inside the cell for loop. Now instead of putting 'Rolf Smith' in here we're going to put the cell contents. Notice that we're not using the row contents anywhere inside our HTML; we're only using that to iterate over it so that we can get every cell out of it. Now we can delete all of these other table rows. Now you can see that we've got here a table row that draws a table header for every element in our headings tuple and then we've got a for loop that draws table rows and the contents of each row is each cell inside that row of data. Now I'm going to restart my application and you can see the contents are identical, but you can see if we go to app.py in here and add a couple more rows of data when we restart our app they show up here immediately without us having to change the template at all. We can also add more headings and more elements to each tuple to display more columns in our table.
Adding styles: static folder, CSS linking, and BEM classes
Let me show you real quick how we can style this table a bit better. First of all I'll open my sidebar and then I'm going to create a new folder called static at the top level, so that's in my project folder in the same folder that app.py is. So now I've got the app.py, the templates and the static folders all in the same place, and in here I'm going to create styles.css. This is going to be my CSS file that I'm going to link to my HTML file so that the styles are applied to this table. How do we link CSS files to HTML files in Flask? Very easy. We'll just do a link element where the rel is stylesheet and the href is equal to /static/styles.css and then we'll close that link. If you know a bit more about Flask and you attempted to use the url_for helper here, feel free to do that, but it's not the focus of this video so we're going to stick to this. Whenever you create a static folder in Flask at the top level of your application it automatically serves all its contents so they are accessible by any browser that's accessing the website, so we can just access it like this and it'll just work. Let's go back to styles.css and I'll close this sidebar because we don't need it anymore. The first thing that we want to do with basically any table is color the even rows with a slightly different color so that it's easier to scan through the table. What I'm going to do is I'm going to type 'tr' and then in here we're going to do 'background-color: #e5e5e5'. What this will do is it will color everything using this new background color just like that. If we use the pseudo selector 'nth-child(even)' then it'll only do that on the even rows. You can see them there. It's generally bad practice to target elements directly using CSS; instead we normally prefer to target them using classes. So let me go to my HTML document and give each of my elements a class. My table is going to have a class of 'table'. This first table row that contains the headings is going to have a class of 'table__header'. Here I'm using the BEM CSS methodology to give class names to my elements; feel free to read up on that. I'll leave a link in the description of this video. Here I'm going to give this a class of 'table__cell'. These rows that we're creating programmatically are going to have a class of 'table__row' and all of these table data elements are going to have a class of 'table__cell'. So you can see that basically all my cells have a class of table__cell, the header has a class of table__header, every row has a class of table__row, and the table itself is the table. Now we can go to styles.css and target these appropriately using .table__row. I want my headers to be left aligned so I'm going to do .table__header and I'm going to do text-align: left. Doing this is going to move the headers over to the left, but you can see that everything is very squished together so I'm going to do .table__cell and give them a padding of 8 pixels. Now everything is a bit more separated. Finally we may also want to give some styles to our table. We can do border-spacing: 0 and that is going to get rid of all the borders between our cells. If we give our table a bit of margin that is going to separate the table from other elements in case this belongs inside a main website. We can also give the table a background color so that we can tell it apart from the background.
Next steps, macros, and outro
All right that's everything for this video. Something that you might want to do later on as you learn more Jinja2 is extract some of the HTML building into Jinja2 macros. We'll talk more about those macros in a later video as well. Thank you so much for joining me in this video. I hope you've enjoyed it. Remember to check out our channel, subscribe and like the video if you can, and I'll see you in the next one.