Django Custom Template Tags

Django's built-in template tags like {% if %}, {% for %}, and filters like {{ name|upper }} are very useful. But sometimes you need your own custom logic inside a template — a calculation, a format conversion, or a custom display rule. Django lets you create your own Custom Template Tags and Filters for exactly this purpose.

What are Template Tags and Filters?

  • Template Filters — Applied to a variable to transform its output. They use the pipe character |. Example: {{ name|upper }} converts "rahul" to "RAHUL".
  • Template Tags — More powerful pieces of logic inside {% %} tags. They can do more complex operations like loops, conditions, or even execute Python logic.
Example: Think of a filter as a photo filter on your phone camera. You take a photo (the raw variable) and apply "Sepia" (filter) to change how it looks without changing the original photo. A template tag is more like a smart camera feature — it can detect faces, apply multiple effects, and do complex operations in one shot.

Setting Up the templatetags Folder

All custom tags and filters must live inside a special folder called templatetags inside your app:


school/
├── templatetags/         <-- Create this folder manually
│   ├── __init__.py       <-- Empty file — makes this a Python package
│   └── school_filters.py <-- Your custom tags and filters go here
├── models.py
├── views.py
└── ...

The __init__.py file must be present (even if empty) — without it, Django will not recognize the folder as a package.

Creating a Custom Filter

Let us create a custom filter that truncates text to a given number of words (useful for showing a preview of a long description):


# school/templatetags/school_filters.py

from django import template

register = template.Library()   # You must create this register object first

@register.filter(name='word_limit')
def word_limit(value, num_words):
    """Truncate text to a given number of words."""
    words = value.split()
    if len(words) <= num_words:
        return value
    return ' '.join(words[:num_words]) + '...'

Now use it in a template:


{% load school_filters %}

<p>{{ student.bio|word_limit:20 }}</p>

This displays only the first 20 words of the bio, followed by "..." if the text is longer.

Example: This filter is like an editor trimming a long article to a short teaser for the newspaper front page. The full article exists, but the front page only shows the first few words to catch the reader's attention.

More Custom Filter Examples

Filter — Convert marks to a Grade Letter


@register.filter(name='marks_to_grade')
def marks_to_grade(marks):
    """Convert a numerical mark to a grade letter."""
    if marks >= 90:
        return 'A+'
    elif marks >= 80:
        return 'A'
    elif marks >= 70:
        return 'B'
    elif marks >= 60:
        return 'C'
    else:
        return 'F'

Use in template:


{% load school_filters %}
<p>Grade: {{ student.marks|marks_to_grade }}</p>

Filter — Format a phone number


@register.filter(name='format_phone')
def format_phone(phone):
    """Format a 10-digit number as XXX-XXX-XXXX."""
    phone = str(phone)
    if len(phone) == 10:
        return f'{phone[:3]}-{phone[3:6]}-{phone[6:]}'
    return phone

Creating a Simple Template Tag

A simple tag is a function that returns a string value, which is then inserted into the template:


# school/templatetags/school_filters.py

from django import template
from django.utils import timezone

register = template.Library()

@register.simple_tag
def current_year():
    """Return the current year."""
    return timezone.now().year

Use in template:


{% load school_filters %}

<footer>
    <p>&copy; {% current_year %} My School. All rights reserved.</p>
</footer>

This automatically shows the current year in the footer — no need to update it manually every year.

Creating an Inclusion Tag — A Mini Template Inside a Template

An inclusion tag renders a separate template and inserts it into the page. This is perfect for reusable UI components like a navigation menu, a sidebar, or a notification widget.


# school/templatetags/school_filters.py

from django import template
from school.models import Student

register = template.Library()

@register.inclusion_tag('snippets/top_students.html')
def show_top_students(count=5):
    """Show the top N students by marks."""
    top_students = Student.objects.order_by('-marks')[:count]
    return {'students': top_students}

Create the mini template templates/snippets/top_students.html:


<ul>
{% for student in students %}
    <li>{{ student.name }} — {{ student.marks }} marks</li>
{% endfor %}
</ul>

Now use it anywhere in any template:


{% load school_filters %}

<h3>Top 5 Students</h3>
{% show_top_students 5 %}
Example: An inclusion tag is like a reusable rubber stamp. You create the stamp design once (the mini template), and can press it anywhere on any document (any main template) whenever needed — instantly adding the same formatted content each time.

Loading Custom Tags in a Template

Every template that uses custom tags or filters must load them at the top using {% load %} with the name of your file (without .py):


{% load school_filters %}

If you want custom tags available in every template without manually loading them, add the file to builtins in settings.py:


TEMPLATES = [{
    ...
    'OPTIONS': {
        'builtins': [
            'school.templatetags.school_filters',  # Always available in all templates
        ],
    },
}]

Django's Built-in Filters for Quick Reference

Django comes with many useful built-in filters you should know:

  • {{ value|upper }} — Converts text to uppercase.
  • {{ value|lower }} — Converts text to lowercase.
  • {{ value|title }} — Capitalizes the first letter of each word.
  • {{ value|truncatewords:30 }} — Truncates to 30 words.
  • {{ value|date:"d M Y" }} — Formats a date (e.g., 15 Jan 2025).
  • {{ value|default:"Not available" }} — Shows a fallback if value is empty.
  • {{ value|length }} — Returns the length of a string or list.
  • {{ value|floatformat:2 }} — Formats a decimal to 2 decimal places.
  • {{ value|linebreaks }} — Converts newlines to HTML paragraph tags.
  • {{ value|safe }} — Marks HTML as safe (stops Django from escaping it).

Quick Recap

  • Create a templatetags/ folder inside your app with an empty __init__.py.
  • Always create a register = template.Library() object in your tags file.
  • Use @register.filter to create custom filters applied with the pipe | character.
  • Use @register.simple_tag to create tags that return a value.
  • Use @register.inclusion_tag to create tags that render a mini sub-template.
  • Always load your custom tags with {% load your_file_name %} at the top of every template that uses them.

Leave a Comment

Your email address will not be published. Required fields are marked *