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().