Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 17

Template Tags and Filters in Django

Recommended resources

Hello! Welcome back to your Django journey.

In the last lesson, we focused on bridging the gap between your Python logic and your HTML templates by passing context data from views. You learned how to package data into a dictionary and access it in the template using {{ variable }} syntax.

This lesson takes the next logical step. Now that you can get data into your templates, you'll learn how to control and format it once it's there. We'll explore two powerful features of the Django Template Language (DTL): template tags and template filters. This will allow you to implement logic, create robust URLs, and format your data for a clean presentation.

This lesson directly addresses the learning outcome: Apply template tags (e.g., {% url %}) and filters to control logic and formatting.

Django Template Rendering Process
This illustration shows how Django takes your HTML, combines it with the logic from template tags (`{% %}`) and the data formatting from filters (`{{ value|filter }}`), and renders the final web page.

1. The Building Blocks: Tags vs. Filters

Before we dive in, let's clarify the difference between tags and filters.

  • Tags ({% tag %}): These provide the logic and control flow inside your template. Think of them as the template language's keywords and functions. You've already used {% extends %} and {% for %}. Today, we'll cover tags for conditional logic and, most importantly, for creating URLs.
  • Filters ({{ variable|filter }}): These are used to modify how a variable is displayed. They are simple transformations you can apply to your data right before it's rendered. For example, making text uppercase or formatting a date.

2. Template Tags: Adding Logic to Your Templates

Template tags are your tools for making templates smart. They handle everything from loops and conditional statements to creating dynamic URLs.

Looping and Conditional Rendering

You've already seen the {% for %} loop. A common requirement when looping is to show a different message if the list you're iterating over is empty. While you could wrap your loop in an {% if %} block, Django provides a more elegant tag for this: {% empty %}.

Let's also look at the {% url %} tag, which is one of the most important tags for building maintainable applications. Hard-coding URLs in your templates (e.g., <a href="/tasks/3/">) is a bad practice. If you ever change that URL structure in urls.py, you have to find and replace it in every single template. The {% url %} tag solves this by dynamically generating the URL based on the name you gave your URL pattern.

The following video provides an excellent, practical demonstration of these concepts.

Django - Detail Pages & the {% url %} template tag!

The video "Django - Detail Pages & the {% url %} template tag!" from BugBytes clearly explains why hard-coding URLs is fragile and how the {% url %} tag provides a robust solution. It also gives a great example of using {% for...empty %}.

Watch from 05:14 to 13:37. Pay close attention to: How the {% url %} tag uses the name defined in your urls.py file. The concept of namespacing URLs (e.g., {% url 'polls:detail' ... %}) to avoid conflicts between different apps. How to use {% empty %} inside a for loop to handle cases with no data.

Key takeaways from the video:

  • Avoid Hard-coding URLs: Always use {% url 'name_of_url' %}. This makes your project much easier to maintain.
  • Use Namespacing: As your projects grow, you'll have multiple apps. To prevent URL name collisions (e.g., two apps having an index URL), define an app_name in your app's urls.py and reference it like {% url 'my_app:index' %}.
  • Handle Empty States: The {% for ... empty %} block is the cleanest way to display a fallback message when a list is empty.
Test your understanding!

Imagine your project has a users app and a tasks app. Both have a URL pattern named list. How would you create a link specifically to the task list page in a template?

Show answer

Assuming you have app_name = 'tasks' in your tasks/urls.py, you would use the namespaced URL tag:
<a href="{% url 'tasks:list' %}">View Tasks</a>


3. Template Filters: Formatting Your Data

Now that we've covered logic with tags, let's look at presentation with filters. Filters are applied with the pipe character (|) and can even be chained together.

For a comprehensive look at the most common filters, the following article is an excellent reference.

Django Templates: Built-In Tags and Filters

The article "Django Templates: Built-In Tags and Filters" from Real Python offers a clear, well-structured guide to the most useful built-in filters.

Read the section titled "Exploring Key Template Filters". Focus on understanding the syntax and the purpose of filters in these categories: String Filters: upper, lower, cut. List Filters: length, join, pluralize. Date and Time Filters: date, time, timesince.

To see some of these filters in action, the following video gives quick, practical demonstrations.

Try DJANGO Tutorial - 20 - Template Tags and Filters

The video "Template Tags and Filters" by CodingEntrepreneurs provides quick visual examples of applying filters.

Watch from 01:42 to 04:24. This will show you how to apply and chain filters like capfirst and upper, and it introduces the important safe filter for rendering HTML.

A particularly important filter to be aware of is safe. By default, Django escapes all HTML in variables to prevent cross-site scripting (XSS) attacks. This means if a variable contains <b>Hello</b>, it will render as the literal text <b>Hello</b>, not as Hello. The safe filter tells Django "I trust this content, render it as actual HTML." Use it with caution and only on content you generate or have sanitized yourself.


4. Practice: Upgrading Your Task List

Let's apply these new tools to your task list application. We'll add due dates and use tags and filters to display them nicely.

  1. Update your View (tasks/views.py)
    Let's add a datetime object to our dummy data. We'll need to import datetime from Python's standard library.

    
    
    
    # tasks/views.py
    
    from django.shortcuts import render
    from datetime import datetime # Import the datetime module
    
    def tasks_view(request):
    
    
    
        # Add a due_date to each task
        dummy_tasks = [
            {'id': 1, 'title': 'Learn Django Views', 'completed': True, 'due_date': datetime(2024, 8, 1)},
            {'id': 2, 'title': 'Build a Template', 'completed': True, 'due_date': datetime(2024, 8, 5)},
            {'id': 3, 'title': 'Understand Context', 'completed': False, 'due_date': datetime(2024, 8, 10)},
            {'id': 4, 'title': 'create a model', 'completed': False, 'due_date': datetime(2024, 8, 15)},
        ]
        
    
    
    
        # We'll also pass an empty list to test the {% empty %} tag
        notes = []
    
        context = {
            'page_title': 'My To-Do List',
            'tasks': dummy_tasks,
            'task_count': len(dummy_tasks),
            'notes': notes
        }
        
        return render(request, 'tasks/task_list.html', context)
    
  2. Update your Template (tasks/templates/tasks/task_list.html)
    Now, let's use filters to format the title and date, and use the empty tag for our new notes list.

    {% extends "base.html" %}
    
    {% block title %}{{ page_title }}{% endblock %}
    
    {% block content %}
        <h1>{{ page_title }}</h1>
    
        <p>You have {{ task_count }} task{{ task_count|pluralize }}.</p>
    
        <ul>
            {% for task in tasks %}
                <li>
                    <!-- Use the capfirst filter to capitalize the title -->
                    {{ task.title|capfirst }} - 
                    
                    Status: {% if task.completed %}Done{% else %}Pending{% endif %} |
                    
                    <!-- Use the date filter to format the due date -->
                    Due: {{ task.due_date|date:"F j, Y" }}
                </li>
            {% endfor %}
        </ul>
    
        <hr>
        
        <h3>Notes</h3>
        <ul>
            {% for note in notes %}
                <li>{{ note }}</li>
            {% empty %}
                <!-- This will be displayed because the 'notes' list is empty -->
                <li>You have no notes yet.</li>
            {% endfor %}
        </ul>
    {% endblock %}
    
    • |capfirst: Capitalizes the first letter of the task title.
    • |date:"F j, Y": Formats the datetime object into a more readable format (e.g., "August 10, 2024"). You can find all the format codes in the Django documentation.
    • |pluralize: Adds an "s" to the word "task" if task_count is not 1.
    • {% empty %}: Shows a message because the notes list we passed in the context is empty.

Save both files and refresh your browser. You should see your formatted titles, readable dates, and the "no notes" message.


Conclusion

Fantastic work! You have now unlocked the full expressive power of the Django Template Language. By combining context data with tags and filters, you can create dynamic, intelligent, and well-formatted web pages.

Key Takeaways:

  • Template Tags ({% %}): Used for logic and control flow. The {% url %} tag is essential for creating maintainable links.
  • Template Filters (|): Used to format and modify data for display. Common uses include changing text case (upper, capfirst), formatting dates (date), and handling plurals (pluralize).
  • Separation of Concerns: Tags and filters allow you to keep presentation logic inside the template, separate from the business logic in your view.

Preview of the Next Lesson:
Our application's structure and logic are taking shape, but it still looks like a plain HTML document. In the next lesson, we will finally add some style! You will learn how to configure and serve static files like CSS and JavaScript in a Django project, allowing you to create visually appealing and interactive user interfaces.