Django logo

Custom template tags in Django

Django custom tags

The Django template language comes with a number of built-in tags and filters such as {% block %}, {% comment %}, {% extends %}. If you find yourself needing functionality that isn’t covered by this core set of template tags, you can make your own tags that perform custom actions. In this article, you will learn about the different types of tags you can create.

Django provides a number of shortcuts or helper functions that make creating your own template tags easy.

  1. simple_tag: Takes any number of arguments, processes them and returns a string.

  2. inclusion_tag: Takes any number of arguments, processes them and renders another template. Returns the rendered template.

  3. assignment_tag: Sets a variable in the context.

Defining custom template tags

Before you can use custom tags, you first have to define them. The most common place to define template tags is inside a Django app. Create a directory to contain the template tags in the app. Name this folder templatetags. Turn this folder into a Python package by adding an __init__.py file to it.

The next step is to create a module inside the templatetags folder that’ll contain all the custom tags you define. The name of the module file is the name you’ll use to load the tags later. As an example, if your Django App is called Events, you may want to name your custom tag module event_tags.py. Here is an example of what your directory structure should look like:

── events
    ├── __init__.py
    ├── models.py
    ├── templatetags
    │   ├── event_tags.py
    │   └── __init__.py
    └── views.py

Simple Tags

In the example below, you’ll see how to create a simple tag that retrieves the number of events that have been created for a fictional Event model. Edit the event_tags.py file and add the following code:

from django import template

register = template.Library()

from ..models import Event

@register.simple_tag
def total_events():
    return Event.objects.count()

To make this module a valid tag library, you create register as an instance of template.Library(). Next use the @register.simple_tag decorator to define the total_events function as a simple tag and register it. This function’s name can now be used as a tag name in your templates.

To use the custom tag you just created in a template, it has to be made available to the template using the {% load %} tag. You’ll need to use the name of the Python module containing your template tags in the {% load %} tag like this: {% load event_tags %}. Add that to the top of your template.

Here is an example of how you would use total_events in a template:

{% load event_tags %}

<!DOCTYPE html>
<html>
    <head>
        <title>{% block title %}{% endblock %}</title>
    </head>
    <body>
      <div id="sidebar">
        <p>
          This is the Events page.
          {% total_events %} events have been recorded so far.
        </p>
      </div>
    </body>
</html>

As you can see, simple tags process some data and return a value to the template that called them.

Inclusion tags

These template tags display some data by rendering another template. Inclusion tags are defined in a similar way to simple tags. The only difference is that these tags take a path to a template as an argument. I’ll use an example to explain.

Suppose we wanted to display a list of events in some part of an existing template like a sidebar. We would first need to collect the list of events and then pass that list to the right template. Inclusion tags do exactly that.

Edit the event_tags.py file and add the following:

@register.inclusion_tag('events/sidebar.html')
def show_latest_events(count=5):
    latest_events = Event.objects.all().order_by('-id')[:count]
    return {'latest_events': latest_events}

The code above registers an inclusion tag called show_latest_events using @register.inclusion_tag. A path to a template('events/sidebar.html) to be rendered is passed to the register decorator.

The show_latest_events() accepts an optional count parameter that defaults to 5. This will allow you to specify the number of events to display. show_latest_events returns a dictionary of the 5 latest events in descending order. Inclusion tags return a dictionary as opposed to returning a simple value because the values returned by them are used as the context used to render the specified template.

The template used in the inclusion tag above would look something like this:

<ul>
{% for event in latest_events %}
  <li><a href="{% url 'events:event-detail' event.id %}">{{ event.title }}</a></li>
{% endfor %}  
</ul>

Here, you display an unordered list of events using the latest_events variable returned by the template tag. To use this inclusion tag, reference it in a template like this {% show_latest_events %}

Arguments can be passed to inclusion tags, so in this example, if you wanted to display 10 events instead of 5, you could do:

<p>
  This is the Events page.
  {% total_events %} events have been recorded so far.
</p>

<h3>Latest Events</h3>
{% `show_latest_events` 10 %}
</div>

Assignment tags

The last type of custom template tag is the assignment tag. Assignment tags are similar to simple_tags() but they store a tag’s result in a specified context variable instead of directly outputting it. Here’s an example that illustrates how they work:

@register.assignment_tag
def get_current_time(format_string):
    return datetime.datetime.now().strftime(format_string)

Here, you create get_current_time() which returns the current time formatted according to the format_string argument. The result of this tag can then be used as a context variable in a template. To store the result in a variable, call get_current_time, followed by an argument and then use as followed by the variable name you’d like to use. In this case the result of the current time is stored in the_time. After this, you can output the variable where you want to in the template:

{% get_current_time "%Y-%m-%d %I:%M %p" as the_time %}
<p>The time is {{ the_time }}</p>

Conclusion

You’ve seen how to make custom template tags using built in functions that make it easy to make simple tags, inclusion tags, and assignment tags. If the basic features for making custom tags aren’t enough for your needs, Django gives you complete access to the internals required to allow you to write your own template tags from the ground up. The docs contain more detailed information on how to go about this.