Django | Part 7 | Styling Homepage Article Content
The previous article explained how to set up a base template and extend it to the homepage. However, as you will have noticed there are still some final touches that need to be made on the homepage to get it looking like a blog. Specifically, this article will detail how to take the entries from the “Article” model and dynamically insert them into the static Start Bootstrap template that is being used for this project.
To achieve this, this article will teach you the following skills:
- How to use a “with” statement in a Django HTML template
- How to use a “for” statement in a Django HTML template
- How to use an “if” statement in a Django HTML template
How to use a “with loop” in a Django HTML template
The very first article in this series explained why Django was chosen as the web framework for this project. One of the reasons was that it is extremely flexible with its HTML templates. Django allows you to use its many built-in “template tags” to either add in dynamic values that are derived from the website database or overlay conditional formatting and logic. One regularly used one is a “with” statement to set conditional logic that can be used to declare a subset of data.
To use a template tag you must insert the command in between a set of curly brackets and percentages like the below example.
{ % with expression|first as first_item %}
Usually, python manages expression blocks with an indentation. However, as a Django template is based in HTML, the indentation does not represent a code block and there is a need to close the block with an end command. The below example is how you would end the “with” statement.
{% endwith %}
Applying this to the “blog_index.html” template the “first” expression will be used to pull the first entry in the “Article” object to use in the big featured article slot. The “Article” model has been built with the Meta class ordering it by “created_on” descending. This means that the first item in the list of objects will always be the most recent article.
To do this, refer back to the original Start Bootstrap template in the previous article, find the div that makes up the blog entries, and copy it into your template between the {% block content %} template tags.
Directly under the “block content” template tag create a block declaring the first item in the “Article” object to be “featured_article”. Then for the values that are hardcoded into the image, title, time created, and description, create a template tag calling each of the necessary model fields.
How to use a “for loop” in a Django HTML template
The next step is to utilise a “for loop” to iterate through all of the remaining “Article” model entries and add them as the small non-featured article blocks in the Start Bootstrap template. Using a for loop in a Django HTML template is similar to how you would in a normal python script, with a few minor tweaks. It starts with the declaration of for followed by the name you are calling the indexing variable, and finally followed by the object that is to be iterated through. In this case, the articles object is to be looped through, calling the index variable in each loop “article”. It will look like the code block below in the template.
{% for article in articles %}
Extend the existing previous “with articles|first” block by starting a for loop. Then paste one of the divs for the smaller non-featured article blocks in the Start Bootstrap template, replacing all of the value fields with the article index followed by the corresponding field names as you did with the featured article above. At the end of the block, just before the “{% endwith %}” statement, close the for loop with an “{% endfor %}” statement.
How to use an “if” statement in a Django HTML template
The last finishing touch for the homepage is limiting the number of small non-featured articles that appear on the homepage. Currently, the for loop will iterate through every one of the objects in the “articles” model, which if there are a lot of articles will result in slow load times and a pretty poor user experience. In this example, the number of articles that will appear under the featured article will be four. An “if” statement is the best way to achieve this, in conjunction with a counter. The for loop counter will keep track of the number of iterations, starting with the integer one, and adding to it on every loop. That way once the counter gets to five, the if statement can break the loop. In action, it will look like the below.
{% if forloop.counter <= 4 %}
In addition to this, we want to skip the first item in the loop, as that article has already been put on display as the feature article. There are many ways to do this, but I find the most simple is to simply add a “not equal to” clause to the if condition as well. Note that the counter has also been changed to five as even though it won’t show the first item, it will still be counted in the loop.
{% if forloop.counter <= 5 and article != featured_article %}
Close off the if loop with the {% endif %} command right before the {% endfor %} command. With all of this complete, your template code for your blog index should look like the code block below.
{% extends "base.html" %}
{% block content %}
<!-- Blog entries-->
{% with articles|first as featured_article %}
<div class="col-lg-8">
<!-- Featured blog post-->
<div class="card mb-4">
<a href="#!"><img class="card-img-top" src="{{featured_article.header_image}}" alt="..." /></a>
<div class="card-body">
<div class="small text-muted">{{featured_article.updated_on}}</div>
<h2 class="card-title">{{featured_article.title}}</h2>
<p class="card-text">{{featured_article.description|slice:":200"}}...</p>
<a class="btn btn-primary" href="#!">Read more →</a>
</div>
</div>
<div class="row">
{% for article in articles %}
{% if forloop.counter <= 5 and article != featured_article %}
<div class="col-lg-6">
<div class="card mb-4">
<a href="#!"><img class="card-img-top" src="{{article.header_image}}" alt="..." /></a>
<div class="card-body">
<div class="small text-muted">{{aticle.updated_on}}</div>
<h2 class="card-title h4">{{article.title}}</h2>
<p class="card-text">{{article.description|slice:":100"}}...</p>
<a class="btn btn-primary" href="#!">Read more →</a>
</div>
</div>
</div>
{% endif %}
{% endfor %}
</div>
</div>
{% endwith %}
{% endblock %}
With the template saved, run the server to see this new styling applied to the article content on the homepage that you introduced in the last session. With this complete, the homepage should be taking shape and clearly articulate the purpose of the blog as well as display the featured content. The next article will move from the homepage and focus on building and designing a view and template to display the articles themselves.