Custom Template Tags & Filters

A custom template tag or filter is a plain Python function, registered with Django's template library, that lets your own templates transform a value or compute new output beyond the built-in tags.

Learn Custom Template Tags & Filters in our free Django course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick…

Part of the free Django course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.

In this lesson you'll build a templatetags package and write all three kinds of extension: a filter that reshapes a value, a simple_tag that returns a computed value, and an inclusion_tag that renders a small template from a returned context — then load and use each one in a template.

A filter is a function that takes a value, optionally one argument, and returns a transformed value. You write it in a templatetags package, decorate it with @register.filter , and apply it in a template with the pipe syntax. First you need the package itself — a templatetags folder with an empty __init__.py inside your app.

Inside blog_extras.py you create a library and register your filters on it:

Then load the library at the top of a template and apply the filters with the pipe:

A simple_tag is a function that returns a value and is invoked with the percent-brace tag syntax rather than the pipe. Unlike a filter, it can take any number of positional and keyword arguments, which makes it perfect for computations that need more than one input.

Call it in a template with the tag syntax — and you can capture the result into a variable with as :

An inclusion_tag renders a small template instead of returning a plain value. You decorate the function with @register.inclusion_tag("some_template.html") ; the function builds and returns a context dict , and Django renders the named template with that context, inserting the result wherever the tag appears.

The small template it renders, blog/tags.html :

And calling it from any page is a single tag — no HTML strings in your Python:

A filter always receives the piped value as its first argument. Fill in the blank so the filter is called with word first, then the argument.

❌ "'blog_extras' is not a registered tag library"

Django can't find the library — usually a missing templatetags/__init__.py , a wrong filename, or you forgot to restart the server.

✅ Fix: ensure templatetags/__init__.py exists, the module name matches what you {' '} , the app is in INSTALLED_APPS , then restart the server.

You used the filter without loading its library at the top of the template.

✅ Fix: add {' '} to the top of the template before you use the filter.

❌ "takes 1 positional argument but 2 were given"

You passed a colon argument to a filter whose function only declares the value parameter.

✅ Fix: add a second parameter to the function, e.g. def truncate_chars(value, count): , so it can accept the argument after the colon.

Write a money simple_tag, run it for real, then build the two template lines that load the library and call the tag.

Lesson complete — you can extend the template language!

You built a templatetags package, wrote a @register.filter applied with the pipe, a @register.simple_tag that returns a value, and a @register.inclusion_tag that renders a sub-template from a context dict — and you know they're all just plain Python functions you load with {' '} .

🚀 Up next: Checkpoint: Models & the ORM — review everything you've learned about models and querying before moving on.

Practice quiz

Where must custom template tags and filters live to be discoverable?

  • In settings.py
  • Inside the project's urls.py
  • In a file named tags.py at the project root
  • In a templatetags package inside an installed app

Answer: In a templatetags package inside an installed app. Django only scans a templatetags package (with __init__.py) inside an installed app.

What object do you create to register tags and filters on?

  • template.Registry()
  • django.Tags()
  • template.Library()
  • register.Module()

Answer: template.Library(). You create register = template.Library() and decorate functions with it.

Which decorator registers a function used with the pipe, as value|name?

  • @register.filter
  • @register.simple_tag
  • @register.inclusion_tag
  • @register.pipe

Answer: @register.filter. @register.filter registers a filter applied with the pipe syntax in a template.

For a filter used as {{ post.body|truncate_chars:10 }}, what are the function's arguments?

  • truncate_chars(10, post.body)
  • truncate_chars(post.body, 10)
  • truncate_chars(10) only
  • truncate_chars(post.body) only

Answer: truncate_chars(post.body, 10). The piped value is the first argument and the colon argument is the second: truncate_chars(post.body, 10).

How is a simple_tag invoked in a template?

  • With the pipe, as value|tag
  • Inside double braces, as {{ tag }}
  • With the tag syntax, as {% tag arg %}
  • It cannot be called from a template

Answer: With the tag syntax, as {% tag arg %}. A simple_tag is called with the {% tag ... %} syntax, never with the pipe.

What advantage does simple_tag have over a filter?

  • It can take any number of positional and keyword arguments
  • It runs before the template loads
  • It does not need {% load %}
  • It can only return None

Answer: It can take any number of positional and keyword arguments. Unlike a filter (value plus at most one arg), a simple_tag accepts many positional and keyword args.

What does a function decorated with @register.inclusion_tag return?

  • An HttpResponse object
  • A finished HTML string
  • Nothing — it prints directly
  • A context dict used to render a named template

Answer: A context dict used to render a named template. An inclusion_tag returns a context dict, and Django renders the named template with it.

Which tag must be loaded before using tags from blog_extras.py?

  • {% import blog_extras %}
  • {% load blog_extras %}
  • {% use blog_extras %}
  • {% require blog_extras %}

Answer: {% load blog_extras %}. {% load blog_extras %} makes that library's tags and filters available in the template.

Which error means Django could not find the library you tried to load?

  • TemplateDoesNotExist
  • NoReverseMatch
  • 'blog_extras' is not a registered tag library
  • ImproperlyConfigured: missing register

Answer: 'blog_extras' is not a registered tag library. That error usually means a missing __init__.py, wrong filename, app not installed, or no server restart.

Which statement about custom tags and filters is true?

  • They are all ordinary Python functions registered on a template.Library()
  • They must be written in a special DSL, not Python
  • Filters can return only strings, never numbers
  • An inclusion_tag returns a raw HTML string

Answer: They are all ordinary Python functions registered on a template.Library(). Filters, simple_tags, and inclusion_tags are plain Python functions registered on a Library().