Styling Flask Jinja2 Templates With Bootstrap, CSS, and IF Logic

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

Styling & Partials

Now that we have two pages and templates set up with Bootstrap for CSS, we can work on making the application look a little better.

Let's add in a navbar and some basic bootstrap content to our template.

Inside of templates/base_layout.html, above the block for content, we'll add in a simple Bootstrap navbar that links to the home page of the application

    <nav class="navbar navbar-light bg-light justify-content-between">
        <a class="navbar-brand">Stock App</a>
        <ul class="navbar-nav mr-auto">
            <li class="nav-item">
                <a class="nav-link" href="{{ url_for('index') }}">Home</a>
            </li>
        </ul>
    </nav>

This navigation bar has a link to the homepage, but when we are on the home page, we would want to make sure that the "Home" link is marked is highlighted differently than other links. Bootstrap provides us with a means to do that by adding the class active to the <li> containing the link. Since this navbar is defined within base_layout.html, we'll need to dynamically figure out if we are on the home page or not. Flask provides us with some information about the current request (like what page we are rendering) in an object called request (that can be imported from Flask). Like url_for, request is another object that is available directly in Jinja thanks to Flask.

Ideally we'll want an if statement within this template where the logic is

"If the current page is the home page, then the class for li should be nav-item active, and other wise it should just be nav-item. Jinja provides us with an if block so we can write the outline of the template code already. However, we'll need to use a slightly different syntax from the double curly braces we've used before. The double curly braces we've used before asks Jinja to evaluate the content within the braces. Instead we'll use {% %} to specify that we are using Jinja control flow features.

<li class="nav-item {% if ____ %} active {% endif %}">

The request object provides us with the name of the current route we are hitting in request.url_rule.endpoint, so we could do <li class="nav-item {% if request.url_rule.endpoint == 'home' %} active {% endif %}">. Again, we could directly access the URL path, but using the name of the route is a bit easier to handle over time after there are a lot of paths.

    <nav class="navbar navbar-light bg-light justify-content-between">
        <a class="navbar-brand">Stock App</a>
        <ul class="navbar-nav mr-auto">
          <li class="nav-item {% if request.url_rule.endpoint == 'home' %} active {% endif %}">
            <a class="nav-link" href="{{ url_for('index') }}">Home</a>
          </li>
        </ul>
    </nav>

Now that we have a navigation bar, we should wrap our content block within a container inside of base_template.html so that we can start using the Bootstrap grid system within each of our templates.

      <div class="container mt-3">
          {% block content %}{% endblock %}
      </div>

Our design idea involves rendering the list of stocks on both the homepage and the individual stock page. Since the list of links will be the exact same in both pages, instead of duplicating the HTML code on both template pages, we can create a partial template that only includes the links. Then we can reference the partial template inside both of home.html and stock_quote.html.

To create a partial template, all we need to do is create another HTML file within the templates folder. We can call this template portfolio.html since it renders our portfolio and include this partial template within our other templates. Since we're doing the same action repeatedly over a list of data, we can use a for loop by using the for tag in Jinja. It works similarly to a for loop in Python, but with a syntax similar to how we handled if and endif earlier.

stock-app/templates/portfolio.html
<h1> View your portfolio </h1>

<ul>
    {% for ticker in ['AAPL', 'NTAP', 'FB'] %}
        <li>
            <a href="{{ url_for('view_stock', ticker=ticker) }}">{{ ticker }}</a>
        </li>
    {% endfor %}
</ul>

Then within home.html we can import the partial inside of a column.

stock-app/templates/index.html
{% block content %}
    <div class="row">
        <div class="col-sm">
            <h1>Welcome to StockApp</h1>
            <div> This is a quick way to view the price of stocks </div>
        </div>
        <div class="col-sm">
            {% include 'portfolio.html' %}
        </div>
    </div>
{% endblock %}

This lesson preview is part of the Fullstack Flask: Build a Complete SaaS App with Flask course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.

Unlock This Course

Get unlimited access to Fullstack Flask: Build a Complete SaaS App with Flask with a single-time purchase.

Thumbnail for the \newline course Fullstack Flask: Build a Complete SaaS App with Flask