Doro's Python Life in Words Journal

Creating custom template tags and filter


The Django framework allows you to create your own template tags and filters. You have to integrate the custom template tag and filter file inside the Django application. You create a Python directory named: "templatetags" and create a file for your custom template tags and filter. Please keep in mind to stop the server and restart it after adding a custom template tag directory and file.

Create a custom template tags

A custom template tag can be a tag to execute a QuerySet or any server-side processing that you want to reuse across templates. There are two helper functions, which allow you to easily create template tags:

  • simple_tag: It processes the given data and returns a string.
  • inclusion_tag: It processes the given data and returns a rendered template.

I created a simple template tag to retrieve the total posts that have been recently published on my blog.

# blog/templatetags/blog_tags.py

from django import template

from blog.models import Post


register = template.Library()


@register.simple_tag
def total_posts():
    return Post.published.count()

Legend:

register = template.Library(): Each module containing template tags must define a variable called register to be a valid tag library. This variable is an instance of template.Library, and it's used to register the application's template tags and filters.
@register.simple_tag: This decorator registers this Python function as a custom template ta

<!-- core/templates/base.html -->

{% load static blog_tags %}

<!DOCTYPE html>
<html lang="en">
<body>

  <div id="sidebar">
    <h2>Dori's Python Life in Words</h2>
    <p>This is my blog. I've written {% total_posts %} posts so far.</p>

Legend:
- {% load blog_tags %}: This template tag load your custom template tag file blog_tags.
{% total_posts %}: This template tag executes your custom template tag and displays the total number of posts.

Creating an inclusion template tag

With this custom template tag I want to display a list of posts in the sidebar of my blog. This template tag will render a template to display a list of links of the posts.

# blog/templatetags/blog_tags.py

from django import template

from blog.models import Post

register = template.Library()


@register.inclusion_tag("post/latest_posts.html")
def show_latest_posts(count=5):
    latest_posts = Post.published.order_by("-publish")[:count]
    return {"latest_posts": latest_posts}

Legend:
- inclusion_tag("post/latest_posts.html"): The inclusion_tag() method has the template as parameter which will be rendered by this custom tag.
- show_latest_posts(count=5): The show_latest_posts function takes count as a parameter and the default value is 5. This function retrieves the 5 last published post instances.

We integrate the custom template tag in our base template:

<!-- core/templates/base.html -->

{% load static blog_tags %}

<h3>Latest posts</h3>
{% show_latest_posts 3 %}

And this custom template tag will display a list of 3 posts.

<!-- blog/templates/post/latest_posts.html-->

<ul>
  {% for post in latest_posts %}
  <li>
    <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
  </li>
  {% endfor %}
</ul>

Implement custom template filter to support Markdown syntax

A custom template filter is a Python function that takes one or two parameters. Filters can be chained after each other. They return a value that can be displayed or used by another filter.

We create this custom template filter to enable to use Markdown syntax for the body of our blog posts. Markdown is a plain-text formatting syntax that is very simple to use, and it's intended to be converted into HTML.

I have installed Markdown with: python -m pip install markdown==3.6.

# blog/templatetags/blog_tags.py

import markdown

from django import template
from django.utils.safestring import mark_safe

from blog.models import Post

register = template.Library()

@register.filter(name="markdown")
def markdown_format(text):
    return mark_safe(markdown.markdown(text))

Legend:
- @register.filter(name="markdown"): We register a filter with the filter() method. Here we give the custom template filter the name 'markdown'.
- mark_safe(): This function marks the result as safe HTML and to be rendered in the template. It is a Django function.

<!-- blog/templates/post/detail.html-->

{% extends "base.html" %}
{% load blog_tags %}

{% block content %}
  <h1>{{ post.title }}</h1>

  <p class="date">
    Published {{ post.publish }} by {{ post.author }}
  </p>
  {{ post.body|markdown }}
  <p>
{% endblock %}

Designed by BootstrapMade and modified by DoriDoro