The web framework for perfectionists with deadlines.

  • Documentation
  • ♥ Donate
  • Toggle theme (current theme: auto) Toggle theme (current theme: light) Toggle theme (current theme: dark) Toggle Light / Dark / Auto color theme

Documentation – Until June 15, 2024, get PyCharm at 30% off . All money goes to the DSF!

  • Getting Help
  • Language: en
  • Documentation version: 5.0

How to create custom template tags and filters ¶

Django’s template language comes with a wide variety of built-in tags and filters designed to address the presentation logic needs of your application. Nevertheless, you may find yourself needing functionality that is not covered by the core set of template primitives. You can extend the template engine by defining custom tags and filters using Python, and then make them available to your templates using the {% load %} tag.

Code layout ¶

The most common place to specify custom template tags and filters is inside a Django app. If they relate to an existing app, it makes sense to bundle them there; otherwise, they can be added to a new app. When a Django app is added to INSTALLED_APPS , any tags it defines in the conventional location described below are automatically made available to load within templates.

The app should contain a templatetags directory, at the same level as models.py , views.py , etc. If this doesn’t already exist, create it - don’t forget the __init__.py file to ensure the directory is treated as a Python package.

Development server won’t automatically restart

After adding the templatetags module, you will need to restart your server before you can use the tags or filters in templates.

Your custom tags and filters will live in a module inside the templatetags directory. The name of the module file is the name you’ll use to load the tags later, so be careful to pick a name that won’t clash with custom tags and filters in another app.

For example, if your custom tags/filters are in a file called poll_extras.py , your app layout might look like this:

And in your template you would use the following:

The app that contains the custom tags must be in INSTALLED_APPS in order for the {% load %} tag to work. This is a security feature: It allows you to host Python code for many template libraries on a single host machine without enabling access to all of them for every Django installation.

There’s no limit on how many modules you put in the templatetags package. Just keep in mind that a {% load %} statement will load tags/filters for the given Python module name, not the name of the app.

To be a valid tag library, the module must contain a module-level variable named register that is a template.Library instance, in which all the tags and filters are registered. So, near the top of your module, put the following:

Alternatively, template tag modules can be registered through the 'libraries' argument to DjangoTemplates . This is useful if you want to use a different label from the template tag module name when loading template tags. It also enables you to register tags without installing an application.

Behind the scenes

For a ton of examples, read the source code for Django’s default filters and tags. They’re in django/template/defaultfilters.py and django/template/defaulttags.py , respectively.

For more information on the load tag, read its documentation.

Writing custom template filters ¶

Custom filters are Python functions that take one or two arguments:

  • The value of the variable (input) – not necessarily a string.
  • The value of the argument – this can have a default value, or be left out altogether.

For example, in the filter {{ var|foo:"bar" }} , the filter foo would be passed the variable var and the argument "bar" .

Since the template language doesn’t provide exception handling, any exception raised from a template filter will be exposed as a server error. Thus, filter functions should avoid raising exceptions if there is a reasonable fallback value to return. In case of input that represents a clear bug in a template, raising an exception may still be better than silent failure which hides the bug.

Here’s an example filter definition:

And here’s an example of how that filter would be used:

Most filters don’t take arguments. In this case, leave the argument out of your function:

Registering custom filters ¶

Once you’ve written your filter definition, you need to register it with your Library instance, to make it available to Django’s template language:

The Library.filter() method takes two arguments:

  • The name of the filter – a string.
  • The compilation function – a Python function (not the name of the function as a string).

You can use register.filter() as a decorator instead:

If you leave off the name argument, as in the second example above, Django will use the function’s name as the filter name.

Finally, register.filter() also accepts three keyword arguments, is_safe , needs_autoescape , and expects_localtime . These arguments are described in filters and auto-escaping and filters and time zones below.

Template filters that expect strings ¶

If you’re writing a template filter that only expects a string as the first argument, you should use the decorator stringfilter . This will convert an object to its string value before being passed to your function:

This way, you’ll be able to pass, say, an integer to this filter, and it won’t cause an AttributeError (because integers don’t have lower() methods).

Filters and auto-escaping ¶

When writing a custom filter, give some thought to how the filter will interact with Django’s auto-escaping behavior. Note that two types of strings can be passed around inside the template code:

Raw strings are the native Python strings. On output, they’re escaped if auto-escaping is in effect and presented unchanged, otherwise.

Safe strings are strings that have been marked safe from further escaping at output time. Any necessary escaping has already been done. They’re commonly used for output that contains raw HTML that is intended to be interpreted as-is on the client side.

Internally, these strings are of type SafeString . You can test for them using code like:

Template filter code falls into one of two situations:

Your filter does not introduce any HTML-unsafe characters ( < , > , ' , " or & ) into the result that were not already present. In this case, you can let Django take care of all the auto-escaping handling for you. All you need to do is set the is_safe flag to True when you register your filter function, like so:

This flag tells Django that if a “safe” string is passed into your filter, the result will still be “safe” and if a non-safe string is passed in, Django will automatically escape it, if necessary.

You can think of this as meaning “this filter is safe – it doesn’t introduce any possibility of unsafe HTML.”

The reason is_safe is necessary is because there are plenty of normal string operations that will turn a SafeData object back into a normal str object and, rather than try to catch them all, which would be very difficult, Django repairs the damage after the filter has completed.

For example, suppose you have a filter that adds the string xx to the end of any input. Since this introduces no dangerous HTML characters to the result (aside from any that were already present), you should mark your filter with is_safe :

When this filter is used in a template where auto-escaping is enabled, Django will escape the output whenever the input is not already marked as “safe”.

By default, is_safe is False , and you can omit it from any filters where it isn’t required.

Be careful when deciding if your filter really does leave safe strings as safe. If you’re removing characters, you might inadvertently leave unbalanced HTML tags or entities in the result. For example, removing a > from the input might turn <a> into <a , which would need to be escaped on output to avoid causing problems. Similarly, removing a semicolon ( ; ) can turn &amp; into &amp , which is no longer a valid entity and thus needs further escaping. Most cases won’t be nearly this tricky, but keep an eye out for any problems like that when reviewing your code.

Marking a filter is_safe will coerce the filter’s return value to a string. If your filter should return a boolean or other non-string value, marking it is_safe will probably have unintended consequences (such as converting a boolean False to the string ‘False’).

Alternatively, your filter code can manually take care of any necessary escaping. This is necessary when you’re introducing new HTML markup into the result. You want to mark the output as safe from further escaping so that your HTML markup isn’t escaped further, so you’ll need to handle the input yourself.

To mark the output as a safe string, use django.utils.safestring.mark_safe() .

Be careful, though. You need to do more than just mark the output as safe. You need to ensure it really is safe, and what you do depends on whether auto-escaping is in effect. The idea is to write filters that can operate in templates where auto-escaping is either on or off in order to make things easier for your template authors.

In order for your filter to know the current auto-escaping state, set the needs_autoescape flag to True when you register your filter function. (If you don’t specify this flag, it defaults to False ). This flag tells Django that your filter function wants to be passed an extra keyword argument, called autoescape , that is True if auto-escaping is in effect and False otherwise. It is recommended to set the default of the autoescape parameter to True , so that if you call the function from Python code it will have escaping enabled by default.

For example, let’s write a filter that emphasizes the first character of a string:

The needs_autoescape flag and the autoescape keyword argument mean that our function will know whether automatic escaping is in effect when the filter is called. We use autoescape to decide whether the input data needs to be passed through django.utils.html.conditional_escape or not. (In the latter case, we use the identity function as the “escape” function.) The conditional_escape() function is like escape() except it only escapes input that is not a SafeData instance. If a SafeData instance is passed to conditional_escape() , the data is returned unchanged.

Finally, in the above example, we remember to mark the result as safe so that our HTML is inserted directly into the template without further escaping.

There’s no need to worry about the is_safe flag in this case (although including it wouldn’t hurt anything). Whenever you manually handle the auto-escaping issues and return a safe string, the is_safe flag won’t change anything either way.

Avoiding XSS vulnerabilities when reusing built-in filters

Django’s built-in filters have autoescape=True by default in order to get the proper autoescaping behavior and avoid a cross-site script vulnerability.

In older versions of Django, be careful when reusing Django’s built-in filters as autoescape defaults to None . You’ll need to pass autoescape=True to get autoescaping.

For example, if you wanted to write a custom filter called urlize_and_linebreaks that combined the urlize and linebreaksbr filters, the filter would look like:

would be equivalent to:

Filters and time zones ¶

If you write a custom filter that operates on datetime objects, you’ll usually register it with the expects_localtime flag set to True :

When this flag is set, if the first argument to your filter is a time zone aware datetime, Django will convert it to the current time zone before passing it to your filter when appropriate, according to rules for time zones conversions in templates .

Writing custom template tags ¶

Tags are more complex than filters, because tags can do anything. Django provides a number of shortcuts that make writing most types of tags easier. First we’ll explore those shortcuts, then explain how to write a tag from scratch for those cases when the shortcuts aren’t powerful enough.

Simple tags ¶

Many template tags take a number of arguments – strings or template variables – and return a result after doing some processing based solely on the input arguments and some external information. For example, a current_time tag might accept a format string and return the time as a string formatted accordingly.

To ease the creation of these types of tags, Django provides a helper function, simple_tag . This function, which is a method of django.template.Library , takes a function that accepts any number of arguments, wraps it in a render function and the other necessary bits mentioned above and registers it with the template system.

Our current_time function could thus be written like this:

A few things to note about the simple_tag helper function:

  • Checking for the required number of arguments, etc., has already been done by the time our function is called, so we don’t need to do that.
  • The quotes around the argument (if any) have already been stripped away, so we receive a plain string.
  • If the argument was a template variable, our function is passed the current value of the variable, not the variable itself.

Unlike other tag utilities, simple_tag passes its output through conditional_escape() if the template context is in autoescape mode, to ensure correct HTML and protect you from XSS vulnerabilities.

If additional escaping is not desired, you will need to use mark_safe() if you are absolutely sure that your code does not contain XSS vulnerabilities. For building small HTML snippets, use of format_html() instead of mark_safe() is strongly recommended.

If your template tag needs to access the current context, you can use the takes_context argument when registering your tag:

Note that the first argument must be called context .

For more information on how the takes_context option works, see the section on inclusion tags .

If you need to rename your tag, you can provide a custom name for it:

simple_tag functions may accept any number of positional or keyword arguments. For example:

Then in the template any number of arguments, separated by spaces, may be passed to the template tag. Like in Python, the values for keyword arguments are set using the equal sign (” = ”) and must be provided after the positional arguments. For example:

It’s possible to store the tag results in a template variable rather than directly outputting it. This is done by using the as argument followed by the variable name. Doing so enables you to output the content yourself where you see fit:

Inclusion tags ¶

Another common type of template tag is the type that displays some data by rendering another template. For example, Django’s admin interface uses custom template tags to display the buttons along the bottom of the “add/change” form pages. Those buttons always look the same, but the link targets change depending on the object being edited – so they’re a perfect case for using a small template that is filled with details from the current object. (In the admin’s case, this is the submit_row tag.)

These sorts of tags are called “inclusion tags”.

Writing inclusion tags is probably best demonstrated by example. Let’s write a tag that outputs a list of choices for a given Poll object, such as was created in the tutorials . We’ll use the tag like this:

…and the output will be something like this:

First, define the function that takes the argument and produces a dictionary of data for the result. The important point here is we only need to return a dictionary, not anything more complex. This will be used as a template context for the template fragment. Example:

Next, create the template used to render the tag’s output. This template is a fixed feature of the tag: the tag writer specifies it, not the template designer. Following our example, the template is very short:

Now, create and register the inclusion tag by calling the inclusion_tag() method on a Library object. Following our example, if the above template is in a file called results.html in a directory that’s searched by the template loader, we’d register the tag like this:

Alternatively it is possible to register the inclusion tag using a django.template.Template instance:

…when first creating the function.

Sometimes, your inclusion tags might require a large number of arguments, making it a pain for template authors to pass in all the arguments and remember their order. To solve this, Django provides a takes_context option for inclusion tags. If you specify takes_context in creating a template tag, the tag will have no required arguments, and the underlying Python function will have one argument – the template context as of when the tag was called.

For example, say you’re writing an inclusion tag that will always be used in a context that contains home_link and home_title variables that point back to the main page. Here’s what the Python function would look like:

Note that the first parameter to the function must be called context .

In that register.inclusion_tag() line, we specified takes_context=True and the name of the template. Here’s what the template link.html might look like:

Then, any time you want to use that custom tag, load its library and call it without any arguments, like so:

Note that when you’re using takes_context=True , there’s no need to pass arguments to the template tag. It automatically gets access to the context.

The takes_context parameter defaults to False . When it’s set to True , the tag is passed the context object, as in this example. That’s the only difference between this case and the previous inclusion_tag example.

inclusion_tag functions may accept any number of positional or keyword arguments. For example:

Advanced custom template tags ¶

Sometimes the basic features for custom template tag creation aren’t enough. Don’t worry, Django gives you complete access to the internals required to build a template tag from the ground up.

A quick overview ¶

The template system works in a two-step process: compiling and rendering. To define a custom template tag, you specify how the compilation works and how the rendering works.

When Django compiles a template, it splits the raw template text into ‘’nodes’’. Each node is an instance of django.template.Node and has a render() method. A compiled template is a list of Node objects. When you call render() on a compiled template object, the template calls render() on each Node in its node list, with the given context. The results are all concatenated together to form the output of the template.

Thus, to define a custom template tag, you specify how the raw template tag is converted into a Node (the compilation function), and what the node’s render() method does.

Writing the compilation function ¶

For each template tag the template parser encounters, it calls a Python function with the tag contents and the parser object itself. This function is responsible for returning a Node instance based on the contents of the tag.

For example, let’s write a full implementation of our template tag, {% current_time %} , that displays the current date/time, formatted according to a parameter given in the tag, in strftime() syntax. It’s a good idea to decide the tag syntax before anything else. In our case, let’s say the tag should be used like this:

The parser for this function should grab the parameter and create a Node object:

  • parser is the template parser object. We don’t need it in this example.
  • token.contents is a string of the raw contents of the tag. In our example, it’s 'current_time "%Y-%m-%d %I:%M %p"' .
  • The token.split_contents() method separates the arguments on spaces while keeping quoted strings together. The more straightforward token.contents.split() wouldn’t be as robust, as it would naively split on all spaces, including those within quoted strings. It’s a good idea to always use token.split_contents() .
  • This function is responsible for raising django.template.TemplateSyntaxError , with helpful messages, for any syntax error.
  • The TemplateSyntaxError exceptions use the tag_name variable. Don’t hard-code the tag’s name in your error messages, because that couples the tag’s name to your function. token.contents.split()[0] will ‘’always’’ be the name of your tag – even when the tag has no arguments.
  • The function returns a CurrentTimeNode with everything the node needs to know about this tag. In this case, it passes the argument – "%Y-%m-%d %I:%M %p" . The leading and trailing quotes from the template tag are removed in format_string[1:-1] .
  • The parsing is very low-level. The Django developers have experimented with writing small frameworks on top of this parsing system, using techniques such as EBNF grammars, but those experiments made the template engine too slow. It’s low-level because that’s fastest.

Writing the renderer ¶

The second step in writing custom tags is to define a Node subclass that has a render() method.

Continuing the above example, we need to define CurrentTimeNode :

  • __init__() gets the format_string from do_current_time() . Always pass any options/parameters/arguments to a Node via its __init__() .
  • The render() method is where the work actually happens.
  • render() should generally fail silently, particularly in a production environment. In some cases however, particularly if context.template.engine.debug is True , this method may raise an exception to make debugging easier. For example, several core tags raise django.template.TemplateSyntaxError if they receive the wrong number or type of arguments.

Ultimately, this decoupling of compilation and rendering results in an efficient template system, because a template can render multiple contexts without having to be parsed multiple times.

Auto-escaping considerations ¶

The output from template tags is not automatically run through the auto-escaping filters (with the exception of simple_tag() as described above). However, there are still a couple of things you should keep in mind when writing a template tag.

If the render() method of your template tag stores the result in a context variable (rather than returning the result in a string), it should take care to call mark_safe() if appropriate. When the variable is ultimately rendered, it will be affected by the auto-escape setting in effect at the time, so content that should be safe from further escaping needs to be marked as such.

Also, if your template tag creates a new context for performing some sub-rendering, set the auto-escape attribute to the current context’s value. The __init__ method for the Context class takes a parameter called autoescape that you can use for this purpose. For example:

This is not a very common situation, but it’s useful if you’re rendering a template yourself. For example:

If we had neglected to pass in the current context.autoescape value to our new Context in this example, the results would have always been automatically escaped, which may not be the desired behavior if the template tag is used inside a {% autoescape off %} block.

Thread-safety considerations ¶

Once a node is parsed, its render method may be called any number of times. Since Django is sometimes run in multi-threaded environments, a single node may be simultaneously rendering with different contexts in response to two separate requests. Therefore, it’s important to make sure your template tags are thread safe.

To make sure your template tags are thread safe, you should never store state information on the node itself. For example, Django provides a builtin cycle template tag that cycles among a list of given strings each time it’s rendered:

A naive implementation of CycleNode might look something like this:

But, suppose we have two templates rendering the template snippet from above at the same time:

  • Thread 1 performs its first loop iteration, CycleNode.render() returns ‘row1’
  • Thread 2 performs its first loop iteration, CycleNode.render() returns ‘row2’
  • Thread 1 performs its second loop iteration, CycleNode.render() returns ‘row1’
  • Thread 2 performs its second loop iteration, CycleNode.render() returns ‘row2’

The CycleNode is iterating, but it’s iterating globally. As far as Thread 1 and Thread 2 are concerned, it’s always returning the same value. This is not what we want!

To address this problem, Django provides a render_context that’s associated with the context of the template that is currently being rendered. The render_context behaves like a Python dictionary, and should be used to store Node state between invocations of the render method.

Let’s refactor our CycleNode implementation to use the render_context :

Note that it’s perfectly safe to store global information that will not change throughout the life of the Node as an attribute. In the case of CycleNode , the cyclevars argument doesn’t change after the Node is instantiated, so we don’t need to put it in the render_context . But state information that is specific to the template that is currently being rendered, like the current iteration of the CycleNode , should be stored in the render_context .

Notice how we used self to scope the CycleNode specific information within the render_context . There may be multiple CycleNodes in a given template, so we need to be careful not to clobber another node’s state information. The easiest way to do this is to always use self as the key into render_context . If you’re keeping track of several state variables, make render_context[self] a dictionary.

Registering the tag ¶

Finally, register the tag with your module’s Library instance, as explained in writing custom template tags above. Example:

The tag() method takes two arguments:

  • The name of the template tag – a string. If this is left out, the name of the compilation function will be used.

As with filter registration, it is also possible to use this as a decorator:

If you leave off the name argument, as in the second example above, Django will use the function’s name as the tag name.

Passing template variables to the tag ¶

Although you can pass any number of arguments to a template tag using token.split_contents() , the arguments are all unpacked as string literals. A little more work is required in order to pass dynamic content (a template variable) to a template tag as an argument.

While the previous examples have formatted the current time into a string and returned the string, suppose you wanted to pass in a DateTimeField from an object and have the template tag format that date-time:

Initially, token.split_contents() will return three values:

  • The tag name format_time .
  • The string 'blog_entry.date_updated' (without the surrounding quotes).
  • The formatting string '"%Y-%m-%d %I:%M %p"' . The return value from split_contents() will include the leading and trailing quotes for string literals like this.

Now your tag should begin to look like this:

You also have to change the renderer to retrieve the actual contents of the date_updated property of the blog_entry object. This can be accomplished by using the Variable() class in django.template .

To use the Variable class, instantiate it with the name of the variable to be resolved, and then call variable.resolve(context) . So, for example:

Variable resolution will throw a VariableDoesNotExist exception if it cannot resolve the string passed to it in the current context of the page.

Setting a variable in the context ¶

The above examples output a value. Generally, it’s more flexible if your template tags set template variables instead of outputting values. That way, template authors can reuse the values that your template tags create.

To set a variable in the context, use dictionary assignment on the context object in the render() method. Here’s an updated version of CurrentTimeNode that sets a template variable current_time instead of outputting it:

Note that render() returns the empty string. render() should always return string output. If all the template tag does is set a variable, render() should return the empty string.

Here’s how you’d use this new version of the tag:

Variable scope in context

Any variable set in the context will only be available in the same block of the template in which it was assigned. This behavior is intentional; it provides a scope for variables so that they don’t conflict with context in other blocks.

But, there’s a problem with CurrentTimeNode2 : The variable name current_time is hard-coded. This means you’ll need to make sure your template doesn’t use {{ current_time }} anywhere else, because the {% current_time %} will blindly overwrite that variable’s value. A cleaner solution is to make the template tag specify the name of the output variable, like so:

To do that, you’ll need to refactor both the compilation function and Node class, like so:

The difference here is that do_current_time() grabs the format string and the variable name, passing both to CurrentTimeNode3 .

Finally, if you only need to have a simple syntax for your custom context-updating template tag, consider using the simple_tag() shortcut, which supports assigning the tag results to a template variable.

Parsing until another block tag ¶

Template tags can work in tandem. For instance, the standard {% comment %} tag hides everything until {% endcomment %} . To create a template tag such as this, use parser.parse() in your compilation function.

Here’s how a simplified {% comment %} tag might be implemented:

The actual implementation of {% comment %} is slightly different in that it allows broken template tags to appear between {% comment %} and {% endcomment %} . It does so by calling parser.skip_past('endcomment') instead of parser.parse(('endcomment',)) followed by parser.delete_first_token() , thus avoiding the generation of a node list.

parser.parse() takes a tuple of names of block tags ‘’to parse until’’. It returns an instance of django.template.NodeList , which is a list of all Node objects that the parser encountered ‘’before’’ it encountered any of the tags named in the tuple.

In "nodelist = parser.parse(('endcomment',))" in the above example, nodelist is a list of all nodes between the {% comment %} and {% endcomment %} , not counting {% comment %} and {% endcomment %} themselves.

After parser.parse() is called, the parser hasn’t yet “consumed” the {% endcomment %} tag, so the code needs to explicitly call parser.delete_first_token() .

CommentNode.render() returns an empty string. Anything between {% comment %} and {% endcomment %} is ignored.

Parsing until another block tag, and saving contents ¶

In the previous example, do_comment() discarded everything between {% comment %} and {% endcomment %} . Instead of doing that, it’s possible to do something with the code between block tags.

For example, here’s a custom template tag, {% upper %} , that capitalizes everything between itself and {% endupper %} .

As in the previous example, we’ll use parser.parse() . But this time, we pass the resulting nodelist to the Node :

The only new concept here is the self.nodelist.render(context) in UpperNode.render() .

For more examples of complex rendering, see the source code of {% for %} in django/template/defaulttags.py and {% if %} in django/template/smartif.py .

Additional Information

Support django.

  • Unchained donated to the Django Software Foundation to support Django development. Donate today!
  • Code layout
  • Registering custom filters
  • Template filters that expect strings
  • Filters and auto-escaping
  • Filters and time zones
  • Simple tags
  • Inclusion tags
  • Advanced custom template tags
  • A quick overview
  • Writing the compilation function
  • Writing the renderer
  • Auto-escaping considerations
  • Thread-safety considerations
  • Registering the tag
  • Passing template variables to the tag
  • Setting a variable in the context
  • Parsing until another block tag
  • Parsing until another block tag, and saving contents
  • Prev: How to implement a custom template backend
  • Next: How to write a custom storage class
  • Table of contents
  • General Index
  • Python Module Index

You are here:

  • How to create custom template tags and filters

Getting help

Offline (Django 5.0): HTML | PDF | ePub Provided by Read the Docs .

Django Links

  • About Django
  • Getting Started with Django
  • Team Organization
  • Django Software Foundation
  • Code of Conduct
  • Diversity Statement

Get Involved

  • Join a Group
  • Contribute to Django
  • Submit a Bug
  • Report a Security Issue
  • Getting Help FAQ
  • #django IRC channel
  • Django Discord
  • Official Django Forum
  • Fediverse (Mastodon)
  • Django Users Mailing List
  • Sponsor Django
  • Corporate membership
  • Official merchandise store
  • Benevity Workplace Giving Program
  • Hosting by In-kind donors
  • Design by Threespot & andrevv

© 2005-2024 Django Software Foundation and individual contributors. Django is a registered trademark of the Django Software Foundation.

Custom Tags and Filters in Django Templates

Django Templates: Implementing Custom Tags and Filters

Table of Contents

Setting Up a Django Project

Using django templates, loading modules and third-party tag libraries, building tags and filters, filters as functions, string filters, date filters, using simple tags, escaping content, working with the context, writing inclusion tags, parsing content, rendering content.

Django templates help you manage your web application’s HTML. Templates use a mini-language with variables, tags, and filters. You can conditionally include blocks, create loops, and modify variables before they’re shown. Django comes with many built-in tags and filters, but what if they’re not enough? In that case, write your own! This tutorial covers the ins and outs of writing your own Django template custom tags and filters.

In this tutorial, you’ll learn how to:

  • Write and register a function as a custom filter
  • Understand how autoescaping works in custom tags and filters
  • Use @simple_tag to write a custom template tag
  • Use @inclusion_tag to render a tag based on a subtemplate
  • Write a complex template tag with a parser and renderer

By the end of the tutorial, you’ll be able to write custom filters to modify data in your templates and custom tags that give you access to the full power of Python within your templates.

Free Bonus: Click here to get access to a free Django Learning Resources Guide (PDF) that shows you tips and tricks as well as common pitfalls to avoid when building Python + Django web applications.

Getting Started

To play around with your own Django template custom tags and filters, you’re going to need a Django project. You’ll build dinosoar , a small website with all sorts of dinosaur info. Although the name implies that you’ll only include flying dinos, that’s just for marketing spin. All your favorite heavyweights will be there as well.

If you’ve never set up a Django project before or if you need a refresher, you may want to read Get Started With Django Part 1: Build a Portfolio App first.

Django is a third-party library, so it should be installed in a virtual environment. If you’re new to virtual environments, check out Python Virtual Environments: A Primer . Create and activate a new virtual environment for yourself and then run the following commands:

These commands perform the following actions:

  • Line 1 runs the pip command to install Django.
  • Line 2 creates your new Django project .
  • Line 3 changes the current working directory to the dinosoar project.
  • Line 4 uses the manage.py command to create a Django app called dinofacts , where your main view will live.
  • Line 5 migrates any database changes. Even if you aren’t creating models, this line is necessary because the Django admin is active by default.

With the project created, it’s time to make some configuration changes and write a quick view to help you test your custom tags and filters.

You need to make some changes to your project’s settings to make Django aware of your newly created app and to configure your templates. Edit dinosoar/dinosoar/settings.py and add dinofacts to the INSTALLED_APPS list:

Within the same file, you’ll need to update the DIR value in the TEMPLATES attribute. This tells Django where to look for your template files:

Starting with Django 3.1, the BASE_DIR value that specifies where the project lives is a pathlib object. The change to the DIRS value above tells Django to look in a templates/ subdirectory within your project directory.

Note: If you use Django 3.0 or earlier, you’ll set BASE_DIR using the os.path module. In that case, use os.path.join() to specify the path.

With the settings changed, don’t forget to create the templates/ directory within your project:

It’s time to start writing some code. To test your custom template tags and filters, you’ll need a view. Edit dinosoar/dinofacts/views.py as follows:

Lines 7 to 15 create a dictionary with some sample data. You’ll use this in your templates to test your tags and filters. The rest of this view does something a little unorthodox: it takes a parameter that specifies the name of a template.

The render() function loads and renders a template. Here, the name value gets suffixed with ".html" , turning it into the name of a template to load. This is not something you’d normally do, but the rest of this article shows you a lot of templates. Rather than having to write a new view for each experiment, this single view will accomplish the task.

The last step before writing a template is to register your view as a URL. Edit dinosoar/dinosoar/urls.py so that it looks like this:

Line 8 registers the /show_dino/ URL with the show_dino view. This URL expects an argument called name , which will be turned into the name of the template to load inside the view.

With the view in place, you’re all set to render some HTML. The next step is to create a template. Most HTML pages are rather repetitive, containing boilerplate header information, meta-info about the page, and navigation tools. Django templates use the power of inheritance to minimize the repetition. To see this in action, create dinosoar/templates/base.html :

By defining blocks and extending parent templates, you can avoid a lot of the cookie-cutter duplication that often happens in HTML files across a site. The template above is a base for all future templates in this tutorial.

Many of the examples in this tutorial will be in their own template files. You’ll be creating each one, and each will inherit from the base file above. The first example child file you need to create is dinosoar/templates/eoraptor.html :

This template uses a few common built-in template tags and filters:

  • Line 3 declares that this template inherits from "base.html" by using the {% extends %} tag.
  • Lines 5 and 27 declare a block called content . During the rendering of eoraptor.html , the template engine looks for a block with the same name in its parent. The engine replaces the corresponding block in base.html .
  • Line 13 uses the {% comment %} tag to write a comment. The rendered output will not include the contents of this tag.
  • Lines 21 and 23 define a {% for %} block tag. This works like a for loop in Python. It iterates over the value dinosaurs and renders the line within the block for each member.
  • Line 22 is rendered once for each item in the dinosaurs list. Each value gets put inside HTML <li> tags. Note the lower filter used with the value. Filters get applied to a value through the pipe ( | ) symbol. Filters use a value and then modify the rendered result. The lower filter is similar to the .lower() method in Python, rendering the value as lowercase.

Everything is in place now. Run the Django development server to see the result:

To see the view, visit http://127.0.0.1:8000/show_dino/eoraptor/ . Your result should look like this:

Result of a example template with a comment tag

The comment has disappeared, and the list of dinosaurs is in lowercase.

You can find more information by going over the Django documentation about built-in template tags and filters or by checking out Django Templates: Built-In Tags and Filters .

There are over seventy-five tags and filters built into Django and several modules on top of that, but that still might not be enough for your use case. But before writing your own custom tags and filters, you should first do some research to see if another package meets your needs.

To use a tag or filter that comes with Django but isn’t in the standard set, you need to:

  • Register the package’s Django app
  • Load the template library into your template

Many third-party packages are available as well. Using a third-party package is no different, except that you’d need to install the package first using pip .

A popular package that comes with Django but isn’t part of the built-in library is humanize . This library has filters that change numeric data into more readable forms. Because it ships as part of the contrib module in Django, there’s no additional installation step.

To register the app, update your INSTALLED_APPS list in dinosoar/dinosoar/settings.py :

Create a new template called dinosoar/templates/iggy.html :

The key to using a tag or filter that isn’t built-in is the {% load %} tag you use on line 4. This is the equivalent of an import statement in your Python code.

The iggy.html template uses two filters from humanize :

  • intcomma converts a number into a string with a comma every three digits.
  • intword converts large numbers into their English equivalent.

Visit http://127.0.0.1:8000/show_dino/iggy/ to see the result:

Result of template using django.contrib.humanize

There are a lot of tags in Django, both built-in and included in the contrib module. There are even more third-party libraries out there. But what if you can’t find something that solves your problem? It’s time to do it yourself by writing some Django custom tags and filters.

Custom tags and filters live in your Django app in a templatetags/ directory. You can import any files in this directory into a template using the {% load %} tag. The name of the module you create will be the name you use to load the tag library.

For this project, the structure will look like this:

This directory is a module like any other Python code, so it requires the __init__.py file. The dinotags.py file will contain all the code for your custom tags and filters.

As you’ll soon explore more, filters are functions. Tags can be either functions or classes, depending on their complexity. Just writing the functions and classes isn’t sufficient—you also need to register the code with Django.

Registration requires an instance of a Library class, which you can then use as a decorator to wrap your tags and filters. The following code is a simplified version of the built-in filter lower :

Think about how this example works:

  • Line 1 imports Django’s template module.
  • Line 3 creates an instance of Library used for registration.
  • Line 5 uses the Library instance’s filter method as a decorator. This tells Django that the lower() function is a filter.
  • Lines 6 to 7 define the function implementing the filter. The filtered value is the first argument to the function. This implementation assumes the value is a string. The string’s .lower() method gets called and the result returned. What you return from your filter function gets rendered in the template.

The Library object provides methods for registering tags and filters. You may call these methods directly, but the better way is to use them as decorators. Decorating the function makes it clear to other programmers that it’s registered as a tag or filter.

Writing Django Template Custom Filters

You set up your project and wrote a view to use for testing. Then, you used built-in tags and filters as well as loaded tags from a library. In the previous section, you learned how to register tags and filters. In this section, you’re all set to write your first Django custom filter!

As mentioned previously, filters are Python functions. The most basic filters take a single argument: the value to filter. The result of a filter function gets rendered by the template engine.

To get started, you’ll write a filter that renders a string composed of the first letter of each item in a list. If you haven’t already, you’ll need to set up your template tag file:

With the structure in place, either create or edit the template tag file called dinosoar/dinofacts/templatetags/dinotags.py :

The code above registers a filter called first_letters . The function expects an iterable, like a list. It iterates over the list and builds the result string. If the value to filter is a list of strings, then result is the first letter of each of those strings.

To use this filter in action, create dinosoar/templates/raptor.html :

With your template in place, visit http://127.0.0.1:8000/show_dino/raptor/ to see the result:

Result of template containing first_letter filter

Recall from dinofacts/views.py that the dinosaurs value is a list containing "Tyrannosaurus" , "Stegosaurus" , "Raptor" , and "Triceratops" . The result above is the first letter of each of these mighty reptiles: "TSRT" .

Filters can also take arguments. Now you’ll augment the power of first_letters by writing a filter that returns the n -th letter of each item in an iterable. Add this function to dinotags.py :

There are a few new things going on here:

  • Line 25 adds the name argument to the @register.filter() decorator. This makes the filter’s name in the template different from the implementing function. Here, the filter gets named nth_letters even though the function that implements it is other_letters() . Note that is_safe=True indicates to Django that the output of this filter doesn’t contain characters that will break HTML. You’ll explore more about this below.
  • Line 26 defines the function. The value to filter is the first argument, and the filter’s parameter is the second.
  • Lines 28 to 32 iterate over the value and build the resulting string.
  • Line 29 is a safety check. If you’re looking for the tenth index in an eight-letter string, it’ll use a space ( " " ) instead. Also, if the n -th character isn’t a letter, you use a space to avoid accidentally returning characters that break HTML.
  • Line 34 returns the result string to be rendered.

Using strings inside of HTML safely is a deep topic. HTML consists of strings with certain characters changing how the browser displays the page. You have to be careful about what string data you pass to the rendering engine, and doubly so if the data was user input.

Django extends raw Python strings with a class called SafeString . A SafeString object has additional information in it that indicates whether the template engine should escape it before rendering.

When Django renders a template, parts of the template may be in autoescape mode . These areas automatically escape the values inside, so Django will turn any troublesome characters into the corresponding HTML entity for display. Sometimes the values you’re rendering are supposed to contain HTML, and so they need to be marked safe .

In the example above, the is_safe=True argument to the registration decorator tells Django that this filter promises not to output any troublesome characters. A safe string passed to a filter does not get escaped by Django. The default value for is_safe is False .

Note that is_safe=True is not marking your filter result as safe. That’s a separate step for which you are responsible. The call to .isalpha() above ensures that all output from this function is safe, so there’s no need for an extra step.

Be careful when determining whether your filter is safe or not, especially when removing characters. A filter that removed all semicolons would break HTML entities that depend on semicolons, like &amp; .

To play with the nth_letters filter, create dinosoar/templates/alberto.html :

Visit http://127.0.0.1:8000/show_dino/alberto/ to get the resulting HTML:

Result of template containing nth_letter filter

Explore the text and check that your nth_letters filter works how you’d expect.

The Canadian lizard might not have been king, but you probably still wouldn’t want to meet it in a dark alley.

The data type of a filter’s argument is the data type of the value used inside the template. The most common data type within HTML documents is the string. Django provides a way to coerce the filter’s input into a string, so you don’t have to do this manually. Now you’ll write a new filter that outputs a sentence summarizing the number of instances of a letter in a string.

Add the following to your dinotags.py file:

The @stringfilter decorator on line 41 indicates that this filter only takes strings. Django turns the filter’s value into a string before passing it into the filter. There are some other interesting things going on in this function:

  • Line 40 uses the needs_autoescape parameter in the registration decorator. This tells Django to add another argument to the filter function: autoescape . The value of this argument will indicate whether autoescaping is on or off for the scope of this filter.
  • Line 42 declares the filter function and includes the autoescape argument mentioned above. This argument should default to True so that you’re in autoescape mode if your code calls the function directly.
  • Lines 43 to 44 replace value with the result of conditional_escape() if autoescape is True . The conditional_escape() function escapes the string but is smart enough to not escape something that has already been escaped.
  • Lines 46 to 49 build the returning string. Because the letter_count filter outputs HTML with bold and italic tags, it has to be autoescape-aware. The f-string on line 47 uses the contents of value , which got appropriately escaped in lines 43 to 44, as needed. The result string contains value in italics and the letter count in bold.
  • Line 51 calls mark_safe() on the result variable. Because the filter is outputting HTML that should be displayed, the function must mark the string as safe. This tells Django not to further escape the contents so the bold and italic tags get rendered by your browser.

To test out this filter, create the following in dinosoar/templates/mosa.html :

Fire up your development server and go to http://127.0.0.1:8000/show_dino/mosa/ to see the following results:

Result of a example template with letter_count filter

The @stringfilter decorator is a quick shortcut that ensures your filter will only have to deal with strings. The needs_autoescape argument and its corresponding autoescape argument give you fine-grained control over what the filter does and doesn’t autoescape.

Dates and time zones can be tricky things to deal with. Dealing with them on a website has an added wrinkle: whose time zone? The server’s? The user’s? Something else?

Django has built-in tools to help deal with this problem. Part of Django’s solution is two key settings:

When USE_TZ is True , Django does all date work according to the time zone you set in TIME_ZONE . The default setting for this is UTC .

It’s easy to forget that template rendering happens on the server-side. Each visitor is getting their own page rendered, so it’s natural to think of the browser as being responsible. However, since rendering does happen on the server, the server’s time zone is the time zone used—unless Django’s settings make it otherwise. Neither the server’s time zone nor Django’s settings have to correspond to the user’s time zone.

This makes filters and dates complicated. To assist with this, filter registration supports an argument called expects_localtime . Django converts datetime objects into the configured time zone when expects_localtime is True . To see how this works, add the following code to dinotags.py :

This filter returns a bolded version of the passed in datetime object. There are better ways of doing this without a filter, but that wouldn’t show you the time zone effects. With expects_localtime set to True in the code above, Django will render the page with a datetime object moved into the time zone specified by the TIME_ZONE setting. To play around with this, create dinosoar/templates/ptero.html :

Visit the page http://127.0.0.1:8000/show_dino/ptero/ to see the filter in action:

Result of a example template with bold_time filter

To see the difference, edit dinosoar/dinosoar/settings.py and change the values of USE_TZ or TIME_ZONE and reload the page. Depending on your choices, the time and possibly even the date will change.

Custom filters give you fine-grained control over your HTML output. They enable you to change the appearance of your data through reusable components. However, as filters are data-focused, they’re limited. To have complete control over a block, you need custom tags.

Writing Django Template Custom Tags

Filters operate on a single value modifying how they’re rendered. Tags are much more flexible than that, allowing you to inject or modify blocks of content as well as manipulate the data context.

Like filters, you work with tags by:

  • Declaring them in modules inside an app’s templatetags/ directory
  • Registering them using a Library instance
  • Implementing them as functions

Additionally, for more complex tags, you can use rendering classes instead of functions. This is necessary to implement tags that render blocks.

To make tag writing more straightforward, Django has the @simple_tag decorator. Structurally, this is similar to a filter: you register a function as a tag, and Django renders its return value. Unlike the filter, tags don’t get associated with values. They’re on their own. You’ll start with the simplest of simple tags by editing the dinosoar/dinofacts/templatetags/dinotags.py file:

Django’s {% comment %} tag is a block and requires a lot of typing. The tag above is a more basic version of the same idea: whatever gets passed into the tag as a parameter gets ignored, and Django renders the tag as an empty string. Create dinosoar/templates/rex.html to test your mute tag:

Visit the page http://127.0.0.1:8000/show_dino/rex/ to see the filter in action:

Result of a example template with nop tag

There’s not much to see in the results, and that’s the point. Everything inside the mute tag has been removed.

Tags, like filters, have to be concerned with whether the content they’re generating is safe for HTML or not. Tags created with @simple_tag are automatically autoescaped but still need to have their content marked safe if it contains HTML.

Consider the following tag, which takes a list and renders an HTML bulleted list. Open dinotags.py and add the following function:

This function takes an iterable—such as a list—and wraps each of its items in an HTML <li> block. Note the use of escape() on line 79. You don’t want to trust what’s passed into the tag. The content variable is a list that starts with a <ul> tag, has each item appended, and then ends with the corresponding closing </ul> tag. Everything gets joined together into a string, and the string gets marked safe.

Use make_ul in a template by creating dinosoar/templates/bronto.html :

Visit http://127.0.0.1:8000/show_dino/bronto/ to get the result:

Result of a example template with make_ul tag

Play around with the dinosaurs value from the show_dino() view inside dinosoar/dinofacts/views.py to see how escaping works. For example, add bold tags to "Tyrannosaurus" to make it "<b>Tyrannosaurus</b>" , and you’ll see the tags displayed instead of actually making anything bold.

When your view renders a template, you can pass data to the template engine through a dictionary called Context . All values rendered in a page come from the Context object, and you can get and set them from within a tag. Create a new tag in dinotags.py :

This code is similar to make_ul but with a few key changes:

  • Line 89 adds the takes_context argument to the tag registration call. Setting this to True tells Django to add an argument to the tag’s function call that contains the Context object.
  • Line 90 declares the function for the tag. Note that the context argument comes first. Tags can take a variable number of arguments, so context has to come first.
  • Line 92 accesses the context argument as a dictionary, getting the value for dinosaurs , which is the same list of dinosaurs used in many other examples.
  • Line 98 writes the string "20 tons" to the context using the key "weight" .

Create a new file called dinosoar/templates/apato.html to test this tag:

Note the use of the value weight on lines 13 and 20. The first use is before the {% dino_list %} tag, and the second use is after. As the value for weight is added as a side effect of the tag, the first instance should be undefined and therefore blank.

The scope of context changes is strictly within the rendering engine. Modifying the context dictionary doesn’t affect any original value in the view. Try out this template by going to http://127.0.0.1:8000/show_dino/apato/ :

Result of a example template with dino_list tag

As promised, the sentence Apatosaurus weighed on average ends rather abruptly. The value for weight isn’t assigned until the template engine renders the tag. The use of the context within tags is a powerful tool for communicating between your tags or saving state for a tag that you run multiple times.

The template engine renders whatever your tag function returns. As you have explored in previous examples, you often write HTML snippets inside your tags. Composing HTML inside strings can be cumbersome, so inclusion tags give you another way to accomplish this: your tag itself can use templates. To see how this is done, start by creating the subtemplate dinosoar/templates/sublist.html :

Your tag will use this template. Now you can add the following tag function to dinotags.py :

The combination of the sublist.html template and this new tag achieves the same thing that make_ul did, but with less code. The @inclusion_tag decorator specifies which template to render with this tag, and the tag function returns a dictionary to use as the context within that template.

To see the results, create a test page called dinosoar/templates/brachio.html :

Go to the usual view to see the page http://127.0.0.1:8000/show_dino/brachio/ :

Result of a example template with include_list tag

If you’re writing a tag that uses a lot of HTML, using @inclusion_tag is a better way to keep the HTML separate from the code.

Creating Advanced Custom Tags

Simple tags are a quick way of writing a tag for the rendering engine to replace inline. Something you can’t do with a simple tag is build blocked areas. Consider how {% comment %} and {% endcomment %} are paired together, removing everything between them. In this section, you’ll explore how to build advanced Django custom tags.

To build a paired block tag, you’ll need to implement a class that extends django.template.Node . This class is responsible for rendering the tag. Django provides a utility for parsing the content between paired block tags, which it then passes to your Node class for rendering.

To demonstrate paired block tags, you’ll implement a Markdown rendering tag. A library called mistune has already done the heavy lifting for this. Use pip to install mistune :

At the time of writing this tutorial, mistune has been undergoing an overhaul. The 2.0 version is in beta and is drastically different from the examples shown here. Make sure to install version 0.8.4, or be prepared to adjust the calls to the library.

Note: For a comprehensive guide to using Markdown in Django, check out How to Render Markdown in a Django Application .

Add the following code to dinosoar/dinofacts/templatetags/dinotags.py :

To build a block tag, you need both a function and a class. Here’s how they work:

  • Line 113 registers the do_markdown() function as a tag. Note that it uses the name argument to name the tag and that it’s using the .tag() decorator, not .simple_tag() .
  • Line 114 declares the tag. The arguments are different from a simple tag, taking a parser and a token. The parser is a reference to the template engine’s parser that’s parsing the template. You don’t use the token argument in this case, and you’ll explore it later.
  • Line 115 uses the parser object to continue parsing the template until it sees the end tag, in this case {% endmarkdown %} .
  • Line 116 calls .delete_first_token() to remove the opening tag. What you pass to the Node class is only what’s between the opening and closing tags.
  • Line 117 instantiates the Node class that renders the template, and the template engine passes in the tokens from the parsed tag block.
  • Lines 119 to 121 declare and initialize the Node class.
  • Lines 123 to 126 render the content. For this tag, that involves using mistune to convert the tag block from Markdown into HTML.
  • Line 124 calls .render() on the contents of the block. This ensures that any embedded template content gets handled and allows you to use values and filters inside your embedded Markdown.
  • Line 125 converts the rendered content into a string and then uses mistune to turn that into HTML.
  • Line 126 returns the result to be inserted into the rendered page. Note that the result is not autoescaped. Django expects that you know how to protect your users from HTML exploits if you’re writing an advanced tag.

Now you’ll test this new tag with some Markdown content. Create dinosoar/templates/steg.html :

Load http://127.0.0.1:8000/show_dino/steg/ into your browser to see the finished product:

Result of a example template with markdown tag

The Markdown from within the block tag pair gets rendered as HTML by the template engine. One thing to keep in mind when playing with Markdown is that indentation is meaningful. If the tag and its contents had not been left-justified, the mistune library would not have been able to convert it properly. This is similar to using a <pre> tag in HTML. Suddenly, spacing matters.

It’s time to dive deeper into block tags. To see how the parser deals with the contents of a tag, add the following to dinotags.py :

The contents of shownodes() are quite similar to do_markdown() . The only difference is that this time, the Node class is going to take both token and the parsed content as parameters. The .render() method of ShowNodesNode does the following:

  • Lines 144 to 146 create a list that will contain the results. The list starts out with an HTML bulleted list tag and a title.
  • Lines 148 to 150 iterate through the contents of the token by calling token.split_contents() . This token contains the information from the opening tag, including its arguments. The parts of the token get added to the result as a bulleted sublist.
  • Lines 153 to 155 do something similar, but instead of operating on the token, they operate on the contents of the block tag. Each item in this bulleted sublist will be one of the tokens parsed out of the tag block.

To see how tag parsing works, create dinosoar/templates/tri.html and use {% shownodes %} as follows:

Your {% shownodes %} tag contains some text, a Context value, and a {% comment %} tag. See what your debugging tag does by visiting http://127.0.0.1:8000/show_dino/tri/ :

Result of a example template with shownodes tag

This page shows you a bit more of what’s going on when you write a block-level Django custom tag. The opening tag had two arguments, "pointy face" and "stubby tail" , which can be accessed through token.split_contents() . The parser divides the block content into five pieces:

  • A TextNode object with the opening part of the sentence
  • A VariableNode object representing the value weight that would normally be rendered
  • Another TextNode object, ending the first sentence
  • A child, CommentNode
  • A TextNode object containing the final blank line

Normally in a block tag, you’d call .render() on any child contents, which would resolve weight and remove the comment in this case, but you don’t have to. Anything inside your tag’s block is under your control.

Django is structured to separate business logic from presentation code through the use of views and templates. The template language is intentionally restrictive to help enforce this separation.

The original developers of Django were attempting to separate the work of HTML designers from Python programmers. This doesn’t mean you’re stuck with the built-in mechanisms, though. Django custom template tags and filters give you a valuable weapon in your tool chest.

In this tutorial, you learned:

  • Where custom template tags and filters live
  • How to write a custom filter
  • When autoescaping will modify your results and how to deal with it
  • How to write simple tags with the @simple_tag and @inclusion_tag decorators
  • About advanced custom tags and parsing the contents of a block tag

For more information about Django, go to the Django project home page . For more information about tags and filters, check out the Django documentation, especially the sections on built-in template tags and filters and custom template tags and filters .

There’s also plenty more to learn about Django on the Django for Web Development Learning Path . Dig in, chow down, take a big bite, and become a Djangosaurus Rex.

🐍 Python Tricks 💌

Get a short & sweet Python Trick delivered to your inbox every couple of days. No spam ever. Unsubscribe any time. Curated by the Real Python team.

Python Tricks Dictionary Merge

About Christopher Trudeau

Christopher Trudeau

Christopher has a passion for the Python language and writes for Real Python. He is a consultant who helps advise organizations on how to improve their technical teams.

Each tutorial at Real Python is created by a team of developers so that it meets our high quality standards. The team members who worked on this tutorial are:

Aldren Santos

Master Real-World Python Skills With Unlimited Access to Real Python

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

Join us and get access to thousands of tutorials, hands-on video courses, and a community of expert Pythonistas:

What Do You Think?

What’s your #1 takeaway or favorite thing you learned? How are you going to put your newfound skills to use? Leave a comment below and let us know.

Commenting Tips: The most useful comments are those written with the goal of learning from or helping out other students. Get tips for asking good questions and get answers to common questions in our support portal . Looking for a real-time conversation? Visit the Real Python Community Chat or join the next “Office Hours” Live Q&A Session . Happy Pythoning!

Keep Learning

Related Topics: advanced django web-dev

Keep reading Real Python by creating a free account or signing in:

Already have an account? Sign-In

Almost there! Complete this form and click the button below to gain instant access:

Django Pony

Get the "Django Learning Resources Guide"

🔒 No spam. We take your privacy seriously.

django assignment_tag

DEV Community

DEV Community

Abdelrahman hassan hamdy

Posted on Jul 12, 2023 • Updated on Apr 9

Understanding and Implementing Custom Template Tags in Django

When you're developing a web application with Django, the built-in template tags and filters can handle a variety of tasks. However, sometimes you might need more power and flexibility to process the data you're working with, in which case, Django provides the option to write your custom template tags and filters.

Custom Template Tags

Getting started.

Before we delve into creating custom template tags, let's enhance our example application, Myblog, by adding a new Post detail page. This will involve:

  • Creating a new template for the post detail
  • Refactoring the byline rendering to remove duplicated code
  • Adding a link to the Post detail page in the index.html template
  • Adding a view to fetch and render the new template
  • Adding a URL mapping to the new view

First, create a new file post-detail.html inside the myblog/templates/blog directory, which will extend the base.html template and override the content block. The content for post-detail.html would look like this:

The post_detail view in views.py would be:

from django.shortcuts import render, get_object_or_404

Next, create another new file post-byline.html in the same directory. The content for post-byline.html would look like this:

inside the blog_extras.py

The index.html should now look like this:

Finally, add a new URL mapping in urls.py :

That's all we learned in the previous article

Creating a Simple Custom Template Tag

A simple custom template tag is built with a Python function that can take any number of arguments, even 0. This function is defined in a Python file inside the templatetags directory of a Django app. Let's create a custom tag for a Bootstrap row:

We can now use these tags in our templates:

Accessing the Template Context in Template Tags

So far, we have only examined how to access variables or values that are explicitly passed to a template tag function. However, with minor modifications to the way the tag is registered, we can enable the tag to access all the context variables that are available in the template in which it's used. This can be handy, for instance, when we need to access the request variable frequently without having to explicitly pass it into the template tag each time.

To provide the template tag access to the context, you need to make two modifications to the template tag function:

  • When registering, pass takes_context=True to the register.simple_tag decorator.
  • Add context as the first argument to the template tag function.

Here is an example that demonstrates how we can re-implement the author_details filter as a template tag that doesn't require any arguments:

The usage in the post-byline.html would look like this:

As you can see, we don't need to pass in any variables, although we could pass in arbitrary variables if we wanted. We have access to the template context and can access any variables we need by using it.

While the author_details_tag won't be used in the myblog project, you can still implement it yourself and test it out.

It's important to remember to revert the post-byline.html and blog_extras.py files back to their original state when you're finished. Here's the original version of the author_details filter:

The ability to access the template context within custom tags can be very handy. It allows you to use all the context variables available in the original template, simplifying the use of tags and keeping the code clean and organized.

In the next section, we'll explore inclusion tags, and how you can use them to render one template inside another.

Inclusion Tags

Another way to include a template within another is with the include template tag. For example:

While easy to implement, this approach has a key limitation: included templates can only access variables already in the including template’s context. Thus, any extra variables must be passed in from the calling view. If you use a template in many places, you may end up repeating the data-loading code in several views.

Inclusion tags address this problem. They let you query for extra data within your template tag function, which can then be used to render a template.

Inclusion tags are registered with the Library.inclusion_tag function. This function requires one argument: the name of the template to render. Unlike simple tags, inclusion tags don’t return a string to render. Instead, they return a context dictionary used to render the template during registration.

A useful feature for a blog site is displaying recent posts. You can create an inclusion tag that fetches the five most recent posts (excluding the current post being viewed) and renders a template.

How to Implement:

Start by creating the template to render - post-list.html in the blog/templates/blog directory:

Now, in blog_extras.py , write a recent_posts function that accepts a post argument. Fetch the five most recent Post objects, excluding the Post passed in. Return a dictionary with posts and title keys. Decorate this function with register.inclusion_tag , passing the path to post-list.html :

Finally, use this template tag in the post-detail.html template. For instance:

Reload a post detail page in your browser, and you should see the "Recent Posts" section, provided you have more than one Post object.

As with a simple tag, you can also pass the context to the inclusion tag function by adding a context argument and adding takes_context=True to the decorator call.

The main benefit of using an inclusion tag is that you can pass in specific information to the inclusion tag that is not found in the regular template tag. In this example, a Post object is passed to the recent_posts template tag, enabling the template tag to access any information in the Post object.

Advanced Template Tags

Simple template tags and inclusion tags cover the majority of use cases for custom template tags. However, Django offers advanced template tags for more customization. These tags consist of two parts:

A parser function: Called when its template tag is encountered in a template. It parses the template tag and extracts variables from the context. It returns a template Node subclass.

The template Node subclass: It has a render method, which is called to return the string to be rendered in the template.

The parser function is registered similarly to other types of tags—by being decorated with @register.tag .

Advanced template tags are useful to:

Capture the content between two tags, perform operations on each node, and choose how they’re output. For instance, you can implement a custom permissions template tag that only outputs the content between them if the current user has the correct permissions.

Set context variables. A template tag could be used to set a value in the template context that is then accessible further on in the template.

While these situations are quite specific, advanced template tags come in handy when the simpler ones don't suffice. If you think you need advanced template tags, check out Django's full documentation on advanced custom template tags.

Top comments (0)

pic

Templates let you quickly answer FAQs or store snippets for re-use.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .

Hide child comments as well

For further actions, you may consider blocking this person and/or reporting abuse

artisticmk profile image

Understanding the root causes of stress and burnout in coding

ArtisticMK - Jun 3

luqmanshaban profile image

Extracting Text from Uploaded Files in Node.js: A Continuation

Luqman Shaban - Jun 3

hkp22 profile image

Spec Coder: Your Powerful AI Co-pilot for Supercharged Coding in Visual Studio Code

Harish Kumar - Jun 3

saumya27 profile image

Optimizing Software Development with DevOps Workflows

Saumya - Jun 3

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

  • Python Basics
  • Interview Questions
  • Python Quiz
  • Popular Packages
  • Python Projects
  • Practice Python
  • AI With Python
  • Learn Python3
  • Python Automation
  • Python Web Dev
  • DSA with Python
  • Python OOPs
  • Dictionaries
  • Django Templates
  • variables - Django Templates
  • Django Template Tags
  • extends - Django Template Tags
  • if - Django Template Tags
  • for loop - Django Template Tags
  • comment - Django template tags
  • include - Django Template Tags
  • url - Django Template Tag
  • cycle - Django Template Tags
  • Django Template Filters
  • for ... empty loop - Django Template Tags
  • firstof - Django Template Tags
  • now - Django Template Tags
  • Boolean Operators - Django Template Tags
  • lorem - Django Template Tags

How to create Custom Template Tags in Django ?

Django offers a variety of built-in template tags such as {% if %} or {% block %}. However, Django also allows you to create your own template tags to perform custom actions. The power of custom template tags is that you can process any data and add it to any template regardless of the view executed. You can perform QuerySets or process any data to display results in your templates.

The most common place to specify custom template tags  is inside a Django app. If they relate to an existing app, it makes sense to bundle them there; otherwise, they can be added to a new app. 

Django provides the following helper functions that allow you to create your own template tags in an easy manner:

  • simple_tag : Processes the data and returns a string
  • inclusion_tag : Processes the data and returns a rendered template
  • assignment_tag : Processes the data and sets a variable in the context

Explanation:

 illustration of How to create a custom template tag using an Example. Consider a project named geeksforgeeks having an app named geeks.

Refer to the following articles to check how to create a project and an app in Django.          How to Create Basic Project using MVT in Django ?           How to Create an App in Django ?

Inside your django application (geeks app) directory, create a new directory, name it templatetags, and add an empty __init__.py file to it to ensure the directory is treated as a Python package. Create another file in the same folder and name it  custom_tags.py. The name of the module file is the name you’ll use to load the tags later, so be careful to pick a name that won’t clash with custom tags and filters in another app. The file structure of the django application should look like the following:

In your template you would use the following:

There’s no limit on how many modules you put in the templatetags package. Just keep in mind that a {% load %} statement will load tags for the given Python module name, not the name of the app.

To be a valid tag library, the module(custom_tags.py)  must contain a module-level variable named register that is a template Library instance in which all the tags  are registered. So, near the top of your module, put the following:

Inside the models.py add the following code:

 

After creating this model, we need to run two commands in order to create Database for the same.

We will start by creating a simple tag to retrieve the total count of objects in our model named as YourModel. Edit the custom_tags.py file you just created and add the following code:

   

Inside the urls.py flle of project named geeksforgeeks add the following code

 

Create the folder named templates inside the app directory(geeks) and create the  file named Intro.py and add the following code:

Let’s check what is there on http://localhost:8000/ –

Output – 

django assignment_tag

Django Models Entries in DB – 

django assignment_tag

Please Login to comment...

Similar reads.

  • Django-templates
  • Python Django

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

Building reliability into software and operations

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.

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

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

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:

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:

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:

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:

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:

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:

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:

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:

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.

Django Custom Template Tags And Filters

Here is the folder structure should look like:

Tags look like this: {% tag %}. Tags can be used to create text in the output, control flow by performing loops or logic, and to load external information into the template.

Tags require beginning and ending tags (i.e. {% tag %} ... tag contents ... {% endtag %}).

Django provides about twenty built-in template tags. Here are some of the more commonly used tags

for - Loop over each item in an array.  if, elif, and else - Evaluates a variable, and if that variable is “true” the contents of the block are displayed

Defining own Custom Template Tags:

In Your app_tags.py

register = template.Library(): This refers that you need to make sure, your templates are added to the existing library of tags and filters that Django knows about. This statement gives an instance of the library so you can register your filters. In this post you'll see that I use the handy "@register.assignment_tag" decorator to register it with Django.

The above template tag can be used in template after enabling your custom tags by using "{% load app_tags %}". An example on how to use these functions in your template:

In Your template "example.html"

The above tag provides the response from the template tag "get_result_tag", can be used with the variable "result".

With the use of filters, we can change the text, do arithmetic operations, know the file size, get the date etc.

Here are some of the commonly used filters

length -- To know string, list size({{ value|length }})   date -- Formats a date according to the given format.( {{ value|date:"D d M Y" }}, {{ value|date:"m/d/Y H:i:s"}} )     File Size -- To get the file size in Mb, Bytes( {{ value|filesizeformat }} )     Sorting a Dictionary -- To sort a list of dictionaries with a given key( {{ value|dictsort:"country_id" }} )

Here is the sample code for the custom filter

Here @register will register this custom filter with Django. I'm using this filter to get the modules to count for a given chapter.

We can use this filter in templates like this

You can play with filters also. Here i'm using multiple filter at once.

Here value1, value2 are passes to one_more filter, perform some operations returns those values to custom_filter filter, do the operations.

Create Custom Template Tags in Django: A complete guide

How to create custom template tags in Django

As a Django web developer, there’s nothing quite like the feeling of having everything organized, in its place, and ready to be customized. Custom template tags provide a way to encapsulate repetitive template logic into reusable, modular code that can be easily accessed across your templates.

Before, I would find myself writing HTML code that was cluttered and hard to read when working on a large Django project that had huge number of templates. It was difficult to maintain the code. Up until, I learned to create my own custom template tags. They were easy to make and my templates became much more organized, readable, and maintainable.

In this article, I’ll be sharing my experience and the knowledge I’ve gained about custom template tags in Django. We’ll cover everything from what custom template tags are, how to create them, and how to use them in templates. By the end of this guide, you’ll have a solid understanding of custom template tags in Django, and be able to use them to improve your Django code.

What are template tags in Django?

Template tags in Django are a way to add logic to your templates (.html files). They are written in Python code and are used to perform dynamic actions such as adding custom logic within a template that is not within the capabilities of a normal .html file. Template tags can take arguments, access data from the context, and return values to be included in the template output.

Django template tags allow developers to abstract complex logic and use that logic in template files.

In short, template tags solve a variety of problems that arise when building web applications.

What are custom template tags in Django?

Custom template tags in Django are a feature that allows developers to create their own custom tags that can be used in Django templates. These tags encapsulate complex logic to be reused across multiple templates.

Creating custom template tags helps create implement complex logic such as conditional statements in a template file while helping maintain code readability and organization, and reducing the amount of repetitive code.

Custom template tags are defined in a Django app . They are created using Python in a Python module. Custom template tags can access context data and perform any necessary processing to generate the desired output, which is then passed back to the template for display.

What are the different types of custom template tags in Django?

In Django, you have access to three main types of custom template tags:

What is a simple tag?

A simple tag in Django is a type of custom template tag that takes some data from the context variable, processes it, and returns a string that can be inserted into a template (.html file).

Simple tags do not render a template of their own and are designed to simply process some data and return string data to a .html file.
Here is a simple example of a simple_tag used to display the current date and time on a web page. # create the code for your simple_tag in your Python module like this from django import template from datetime import datetime register = template.Library() @register.simple_tag() def current_time_tag(): return str(datetime.now().time()) # Then use the simple tag in your template like this You are accessing this page at: {% current_time %} # The simple tag will display a simple string showing the current time you're accessing that particular web page. It is as simple as that!

What is an inclusion tag?

An inclusion tag in Django is a type of custom template tag that takes some data from the context and uses the data to render a template. The rendered result can then be inserted into the template. and returns a string that can be inserted into a template (.html file).

Inclusion tags do render a template of their own and are designed to handle complex processing that require a template to be rendered. It is a powerful approach to encapsulating complex logic into reusable code.
Rendering a template in an inclusion tag in Django refers to the process of using data from the context variable and generating the output in the form of HTML content that can be inserted into the template using the custom tag. For example, consider a website with a header that is the same on every page. Instead of duplicating the header code on each page, you could create an inclusion tag that you can use in each of your pages. Here’s an example: # Let's say this is your header code <header> <nav> <a href="/">Home</a> <a href="/about">About</a> <a href="/contact">Contact</a> </nav> </header> # In your Python module with custom template tags, you can create an inclusion tag like this: from django import template register = template.Library() @register.inclusion_tag('header.html') def header_tag(): return {} # Then, in your templates, you can render the header code like this: {% load header_tag %} <html> <body> {% header_tag %} <!-- other content --> </body> </html> The result:

Why create custom template tags in Django?

8 benefits of using custom template tags in django.

Here are 8 reasons why creating custom template tags in Django is important:

We’ve talked much about custom template tags, let’s see how to create these custom tags in your Django projects.

How to create custom template tags in Django

Before you start creating your custom template tags, you need to do two things:

Setting up the environment for creating custom template tags

Here are the detailed steps to setting up your Django project for creating custom template tags:

Step 1: Create a Django application

Navigate into your project root directory and create an app using the following command:

Step 2: Create templatetags directory inside app-level directory

Where you have your app’s files, e.g views.py , models.py , and admin.py, create a new custom tags directory called templatetags. Here’s a simple command to do that:

Step 3: Create an empty __init__.py inside templatetags directory

Step 4: register your new django app inside settings.py file.

To use custom template tags in a Django project, your application that contains the custom tags library must be registered in the INSTALLED_APPS setting in the project’s settings.py file.

Creating a custom template tag step by step

After setting up your development environment, let’s actually create a custom template tag from start to finish. This section is crucial as it provides a hands-on approach to creating custom template tags, allowing you to apply the concepts learned in the previous sections and see the results in action.

Steps to take to create a custom template tag in Django

Here are the steps to create a custom template tag in Django:

Here are the steps showing how to create an example template tag in detail:

Step I> Create a custom template tags library inside templatetags directory

For our Django blog application, here is an example of a custom template tags module for listing all the latest featured posts. Based on the context, the files name for the module should be latest_posts.py

After creating the file, open it using your favorite code editor or IDE.

Step II> Import the necessary module that include django.template

In your new Python module, import the necessary modules that will be used in your file. The default must-have module should be django.template. If you are accessing data from the database , you may also need to import the necessary Django app models here.

Also, create the register object by instantiating it from django.template.Library Here’s how to do it: After importing the necessary moduels add the following line of code in your custom temlplate tags module. register = template.Library()

Step III> Define the custom template tag using the Python function syntax

Define your custom template tag function providing the necessary arguments, the logic, and the desired output.

The function above retrieves the latest 10 blog posts.

Step IV> Decorate your custom template tag with the appropriate decorator

After creating your custom template tag logic, decorate the function with @register.simple_tag or @register.inclusion_tag decorators. Depending on the custom tag type, you can any of the decorators.

For the blog app, here’s how to decorate the get_latest_posts custom function to make it a custom template tag:

Step V: Save your Python file and perform some tests to ensure it works

With that, you should have created a custom template tag that can be used in your templates.

How to create a simple_tag in Django?

Here are the steps to create a simple tag in Django:

How to create an inclusion_tag in Django?

How to register a tag in django.

Here’s how it works in simple steps:

How to use custom template tags in templates

So, you will need to create the templates and then using your custom template tags in those templates.

Create templates in Django?

How to use custom template tags in django templates.

After creating your Django template file, follow these steps to load the custom library and the custom template tags in your .html file:

Step #1: Load the custom tag library in the template file by using the {% load %} tag

For our blog application, you can load the Python module using the following code:

Step #2: Invoke the custom template tag code by using {% %} template tag syntax

Invoke the custom tag in the template code by using the custom tag’s name and any necessary arguments. For example, if you have a custom simple tag called “latest_blog_posts” that takes a count argument to limit the number of posts returned, you would use it in your template code like this: {% latest_blog_posts "John" %} .

The template code above should return all the latest 10 posts in each template that you invoke it.

How to create custom template tags with multiple arguments in Django

Creating custom template tags with multiple arguments in Django involves defining a function that implements the logic for your custom tag and adding the necessary arguments to the function.

For demonstration, let’s create a custom template tag that greets a user by their name and time of the day. Follow these steps:

1. Import the necessary libraries and objects in your custom template tags module

2. define your custom tag function while providing as many arguments as you want for your logic to work, 3. register your custom template tag by decorating it with the appropriate decorator.

In this example, the custom tag function should be decorated with @register.simple_tag .

4. Load your custom library in your template file

5. use your custom tag in the template file while providing the necessary arguments.

In this example, the custom tag can be used in the template code by passing two arguments: a username and a time of the day.

What is the difference between template files and template tags?

Here is a table showing the differences between template files and template tags:

Represent the structure and content of a webpage.Provides additional dynamic functionality within the Django template.
Create as a .html file. They are typically written in HTML.Created inside a Python module, .py file. They are written in Python.
Uses standard template languageUse standard Python programming language
Allow a limited amount of dynamic behavior.Offer a wider range of dynamic behavior and conditionals.
Used to display content.Used to modify, process, and control content.

Whether you’re looking to simplify your code, add custom functionality, or improve the overall user experience of your Django templates, this is the right how-to guide you need to achieve that.

Related Posts

Is virtualenv (venv) necessary for django, how to add two values in django templates, can i use python modules in django, leave a reply cancel reply.

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

Django Tutorial

Display data, django syntax, static files, deploy django, more django, django references, django exercises, django template variables, template variables.

In Django templates, you can render variables by putting them inside {{ }} brackets:

templates/template.html :

Create Variable in View

The variable firstname in the example above was sent to the template via a view:

As you can see in the view above, we create an object named context and fill it with data, and send it as the first parameter in the template.render() function.

Create Variables in Template

You can also create variables directly in the template, by using the {% with %} template tag.

The variable is available until the {% endwith %} tag appears:

You will learn more about template tags in the next chapter.

Data From a Model

The example above showed a easy approach on how to create and use variables in a template.

Normally, most of the external data you want to use in a template, comes from a model.

We have created a model in the previous chapters, called Member , which we will use in many examples in the next chapters of this tutorial.

To get data from the Member model, we will have to import it in the views.py file, and extract data from it in the view:

members/views.py :

Now we can use the data in the template:

We use the Django template tag {% for %} to loop through the members.

Get Certified

COLOR PICKER

colorpicker

Contact Sales

If you want to use W3Schools services as an educational institution, team or enterprise, send us an e-mail: [email protected]

Report Error

If you want to report an error, or if you want to make a suggestion, send us an e-mail: [email protected]

Top Tutorials

Top references, top examples, get certified.

django assignment_tag

Using Custom Tags to Display Dashboard in Django Admin

9cv9 HR and Career Blog | Top Rated by Readers

9cv9 HR and Career Blog | Top Rated by Readers

Small talk about Django Admin

Django Admin is a Django feature that enables the user to manage the contents of the site. It is recommended that this feature is only used by a limited number of trusted authorized users who manage a site, rather than it being built as the main frontend of a website.

Here, Django reads all metadatas from all models registered in the site and provides automatic interface for the site admin. Developers can register their models, define the fields to display, define filters, and much more to make the admin page look more informative. The HTML template for admin pages are provided by Django itself, therefore, developers are given the chance to override these templates and make them interactive and informative even more.

Then, why do we need custom tags?

Tags in Django are special notations of Django’s template language that would help developers when building Django templates. These tags are designed to fulfill the needs of Django website presentation logic. There are two kinds of tag: built-in tags and custom tags. Built-in tags are the tags that Django automatically provides for developers. For a deeper look at built-in ones, you can learn more about them here .

Sometimes, developers find out that there are some functionalities that built-in tags can’t cover. Addressing this need, Django also provides custom tags developers to freely define so as to facilitate any special functionalities. One important use of this tag is that it can be used to provide custom data for our templates.

Understood! Now, where should I start?

Before going any further, we need to first make a Django Project with an app inside it. Let’s say we name the app: sale . Inside this sale app, we need to make a simple model in models.py, such as:

After that, we need to make a templatetags folder inside this sale app folder, with __init__.py inside it. We also need to add the sale app into INSTALLED_APPS in our project settings.py.

All set up! How do I make my first tag?

Our tags should be set up inside the folder templatetags we’ve prepared before. There are three types of custom tags supported by Django: simple tag, inclusion tag, and assignment tag . We’ll try to make one custom tag for each kind.

Simple tag is just like other Django template tags. What’s special about this custom tag is that this tag can receive a value and return a string value. For example, when we need the count of our sale object in our admin page, we can use this tag to get it. Inside our templatetags , we can create a file get_sale_count.py and write this code inside the file:

We can also make another file called get_sale_delivered_count.py to make a tag which can return the count of sale objects with type = 2 or delivered . Here below is the sample code for this file:

The second type of tag is the inclusion tag . We use this type of tag when we want to render an HTML template with context data return by the tag itself. For example, we want to make a dedicated admin page for our sale objects with sale objects as the context data. Let’s say we have our template in sale_admin.html file, we can make a file called sale_admin.py inside our templatetags folder with code like below:

Our third and final type of tag is the assignment tag. This tag is quite similar with simple tag. It can receive input values, and return another value. The difference is this tag can return anything and not only string values. We can use this tag to return a dictionary which we can use for making tables or charts. For example, we want to make a chart that display our sale objects growth by month. For this chart, we need to pass periodical data from our objects to the return value. Below is the sample code that you should write inside chart_sale.py in your templatetags folder.

That code will return context_data variable which will contain 12 objects which represent 12 period in a year with count of objects created in that period.

My tags are done, how do I display them?

In this article, we will override the main dashboard in admin page. To do that, we have to make a templates folder in our project root directory. Also, don’t forget to add templates to TEMPLATES [ ‘DIRS’ ] in settings.py. Inside the templates folder, add another folder called admin. In this folder, we need index.html file that will override the original Django admin dashboard template. On top of the file, we need to use this code to extends base_site template and import our custom tags and some other tags:

For the base template, you can go here and copy the code of the original index.html . After that, we can add inside the {% block content %} section our custom divs. First, let’s try to make a table using our chart_sale tag we have defined before. Here is the sample code that you can place inside the content block.

2019 in the first line is the value we pass to the tag function, and summary is the output variable that contains our tag’s return value. The for block means that for every object in summary , we create a table row containing the object’s information. Here, for example, we display the objects’ periods, total counts, and percentages.

Table is pretty simple, then how about charts?

Making charts is actually not that difficult, and bar charts are especially simple. First, don’t forget to load our tag on top of our template file like we did before while making the table. After that, you can use this code to make your bar chart:

And that’s it! Pretty compact right? You can make it more interesting by adding tooltips or other styling components. You can also decorate your template by overriding the {% block extrastyle %} and fill it with your own styling (<style> HTML tag).

One important management feature that Django provides is Django Admin. Here, authorized admin users can manage the content of their Django website. To make the admin pages more informative, we can override the admin page templates and build our own custom tags to provide custom data for our templates. After that, we can make our own tables and charts to present the data more interactively.

Custom tags

  • https://pypi.org/project/pyexcel-xls/
  • https://docs.djangoproject.com/en/2.2/howto/custom-template-tags/

Django Admin

  • https://github.com/django/django/tree/master/django/contrib/admin/templates/admin
  • https://docs.djangoproject.com/en/2.2/ref/contrib/admin/
  • https://hakibenita.com/how-to-turn-django-admin-into-a-lightweight-dashboard

9cv9 HR and Career Blog | Top Rated by Readers

Written by 9cv9 HR and Career Blog | Top Rated by Readers

At 9cv9, we help firms hire better & jobseekers to get hired. Our blog is well-researched to deliver top data, articles & guides. Check here: blog.9cv9.com

Text to speech

Django 1.7a2 documentation

Custom template tags and filters ¶.

Django’s template system comes with a wide variety of built-in tags and filters designed to address the presentation logic needs of your application. Nevertheless, you may find yourself needing functionality that is not covered by the core set of template primitives. You can extend the template engine by defining custom tags and filters using Python, and then make them available to your templates using the {% load %} tag.

Code layout ¶

Custom template tags and filters must live inside a Django app. If they relate to an existing app it makes sense to bundle them there; otherwise, you should create a new app to hold them.

The app should contain a templatetags directory, at the same level as models.py , views.py , etc. If this doesn’t already exist, create it - don’t forget the __init__.py file to ensure the directory is treated as a Python package. After adding this module, you will need to restart your server before you can use the tags or filters in templates.

Your custom tags and filters will live in a module inside the templatetags directory. The name of the module file is the name you’ll use to load the tags later, so be careful to pick a name that won’t clash with custom tags and filters in another app.

For example, if your custom tags/filters are in a file called poll_extras.py , your app layout might look like this:

And in your template you would use the following:

The app that contains the custom tags must be in INSTALLED_APPS in order for the {% load %} tag to work. This is a security feature: It allows you to host Python code for many template libraries on a single host machine without enabling access to all of them for every Django installation.

There’s no limit on how many modules you put in the templatetags package. Just keep in mind that a {% load %} statement will load tags/filters for the given Python module name, not the name of the app.

To be a valid tag library, the module must contain a module-level variable named register that is a template.Library instance, in which all the tags and filters are registered. So, near the top of your module, put the following:

Behind the scenes

For a ton of examples, read the source code for Django’s default filters and tags. They’re in django/template/defaultfilters.py and django/template/defaulttags.py , respectively.

For more information on the load tag, read its documentation.

Writing custom template filters ¶

Custom filters are just Python functions that take one or two arguments:

  • The value of the variable (input) – not necessarily a string.
  • The value of the argument – this can have a default value, or be left out altogether.

For example, in the filter {{ var|foo:"bar" }} , the filter foo would be passed the variable var and the argument "bar" .

Filter functions should always return something. They shouldn’t raise exceptions. They should fail silently. In case of error, they should return either the original input or an empty string – whichever makes more sense.

Here’s an example filter definition:

And here’s an example of how that filter would be used:

Most filters don’t take arguments. In this case, just leave the argument out of your function. Example:

Registering custom filters ¶

Once you’ve written your filter definition, you need to register it with your Library instance, to make it available to Django’s template language:

The Library.filter() method takes two arguments:

  • The name of the filter – a string.
  • The compilation function – a Python function (not the name of the function as a string).

You can use register.filter() as a decorator instead:

If you leave off the name argument, as in the second example above, Django will use the function’s name as the filter name.

Finally, register.filter() also accepts three keyword arguments, is_safe , needs_autoescape , and expects_localtime . These arguments are described in filters and auto-escaping and filters and time zones below.

Template filters that expect strings ¶

If you’re writing a template filter that only expects a string as the first argument, you should use the decorator stringfilter . This will convert an object to its string value before being passed to your function:

This way, you’ll be able to pass, say, an integer to this filter, and it won’t cause an AttributeError (because integers don’t have lower() methods).

Filters and auto-escaping ¶

When writing a custom filter, give some thought to how the filter will interact with Django’s auto-escaping behavior. Note that three types of strings can be passed around inside the template code:

Raw strings are the native Python str or unicode types. On output, they’re escaped if auto-escaping is in effect and presented unchanged, otherwise.

Safe strings are strings that have been marked safe from further escaping at output time. Any necessary escaping has already been done. They’re commonly used for output that contains raw HTML that is intended to be interpreted as-is on the client side.

Internally, these strings are of type SafeBytes or SafeText . They share a common base class of SafeData , so you can test for them using code like:

Strings marked as “needing escaping” are always escaped on output, regardless of whether they are in an autoescape block or not. These strings are only escaped once, however, even if auto-escaping applies.

Internally, these strings are of type EscapeBytes or EscapeText . Generally you don’t have to worry about these; they exist for the implementation of the escape filter.

Template filter code falls into one of two situations:

Your filter does not introduce any HTML-unsafe characters ( < , > , ' , " or & ) into the result that were not already present. In this case, you can let Django take care of all the auto-escaping handling for you. All you need to do is set the is_safe flag to True when you register your filter function, like so:

This flag tells Django that if a “safe” string is passed into your filter, the result will still be “safe” and if a non-safe string is passed in, Django will automatically escape it, if necessary.

You can think of this as meaning “this filter is safe – it doesn’t introduce any possibility of unsafe HTML.”

The reason is_safe is necessary is because there are plenty of normal string operations that will turn a SafeData object back into a normal str or unicode object and, rather than try to catch them all, which would be very difficult, Django repairs the damage after the filter has completed.

For example, suppose you have a filter that adds the string xx to the end of any input. Since this introduces no dangerous HTML characters to the result (aside from any that were already present), you should mark your filter with is_safe :

When this filter is used in a template where auto-escaping is enabled, Django will escape the output whenever the input is not already marked as “safe”.

By default, is_safe is False , and you can omit it from any filters where it isn’t required.

Be careful when deciding if your filter really does leave safe strings as safe. If you’re removing characters, you might inadvertently leave unbalanced HTML tags or entities in the result. For example, removing a > from the input might turn <a> into <a , which would need to be escaped on output to avoid causing problems. Similarly, removing a semicolon ( ; ) can turn &amp; into &amp , which is no longer a valid entity and thus needs further escaping. Most cases won’t be nearly this tricky, but keep an eye out for any problems like that when reviewing your code.

Marking a filter is_safe will coerce the filter’s return value to a string. If your filter should return a boolean or other non-string value, marking it is_safe will probably have unintended consequences (such as converting a boolean False to the string ‘False’).

Alternatively, your filter code can manually take care of any necessary escaping. This is necessary when you’re introducing new HTML markup into the result. You want to mark the output as safe from further escaping so that your HTML markup isn’t escaped further, so you’ll need to handle the input yourself.

To mark the output as a safe string, use django.utils.safestring.mark_safe() .

Be careful, though. You need to do more than just mark the output as safe. You need to ensure it really is safe, and what you do depends on whether auto-escaping is in effect. The idea is to write filters than can operate in templates where auto-escaping is either on or off in order to make things easier for your template authors.

In order for your filter to know the current auto-escaping state, set the needs_autoescape flag to True when you register your filter function. (If you don’t specify this flag, it defaults to False ). This flag tells Django that your filter function wants to be passed an extra keyword argument, called autoescape , that is True if auto-escaping is in effect and False otherwise.

For example, let’s write a filter that emphasizes the first character of a string:

The needs_autoescape flag and the autoescape keyword argument mean that our function will know whether automatic escaping is in effect when the filter is called. We use autoescape to decide whether the input data needs to be passed through django.utils.html.conditional_escape or not. (In the latter case, we just use the identity function as the “escape” function.) The conditional_escape() function is like escape() except it only escapes input that is not a SafeData instance. If a SafeData instance is passed to conditional_escape() , the data is returned unchanged.

Finally, in the above example, we remember to mark the result as safe so that our HTML is inserted directly into the template without further escaping.

There’s no need to worry about the is_safe flag in this case (although including it wouldn’t hurt anything). Whenever you manually handle the auto-escaping issues and return a safe string, the is_safe flag won’t change anything either way.

Avoiding XSS vulnerabilities when reusing built-in filters

Be careful when reusing Django’s built-in filters. You’ll need to pass autoescape=True to the filter in order to get the proper autoescaping behavior and avoid a cross-site script vulnerability.

For example, if you wanted to write a custom filter called urlize_and_linebreaks that combined the urlize and linebreaksbr filters, the filter would look like:

would be equivalent to:

Filters and time zones ¶

If you write a custom filter that operates on datetime objects, you’ll usually register it with the expects_localtime flag set to True :

When this flag is set, if the first argument to your filter is a time zone aware datetime, Django will convert it to the current time zone before passing it to your filter when appropriate, according to rules for time zones conversions in templates .

Writing custom template tags ¶

Tags are more complex than filters, because tags can do anything.

A quick overview ¶

Above, this document explained that the template system works in a two-step process: compiling and rendering. To define a custom template tag, you specify how the compilation works and how the rendering works.

When Django compiles a template, it splits the raw template text into ‘’nodes’‘. Each node is an instance of django.template.Node and has a render() method. A compiled template is, simply, a list of Node objects. When you call render() on a compiled template object, the template calls render() on each Node in its node list, with the given context. The results are all concatenated together to form the output of the template.

Thus, to define a custom template tag, you specify how the raw template tag is converted into a Node (the compilation function), and what the node’s render() method does.

Writing the compilation function ¶

For each template tag the template parser encounters, it calls a Python function with the tag contents and the parser object itself. This function is responsible for returning a Node instance based on the contents of the tag.

For example, let’s write a template tag, {% current_time %} , that displays the current date/time, formatted according to a parameter given in the tag, in strftime() syntax. It’s a good idea to decide the tag syntax before anything else. In our case, let’s say the tag should be used like this:

The parser for this function should grab the parameter and create a Node object:

  • parser is the template parser object. We don’t need it in this example.
  • token.contents is a string of the raw contents of the tag. In our example, it’s 'current_time "%Y-%m-%d %I:%M %p"' .
  • The token.split_contents() method separates the arguments on spaces while keeping quoted strings together. The more straightforward token.contents.split() wouldn’t be as robust, as it would naively split on all spaces, including those within quoted strings. It’s a good idea to always use token.split_contents() .
  • This function is responsible for raising django.template.TemplateSyntaxError , with helpful messages, for any syntax error.
  • The TemplateSyntaxError exceptions use the tag_name variable. Don’t hard-code the tag’s name in your error messages, because that couples the tag’s name to your function. token.contents.split()[0] will ‘’always’’ be the name of your tag – even when the tag has no arguments.
  • The function returns a CurrentTimeNode with everything the node needs to know about this tag. In this case, it just passes the argument – "%Y-%m-%d %I:%M %p" . The leading and trailing quotes from the template tag are removed in format_string[1:-1] .
  • The parsing is very low-level. The Django developers have experimented with writing small frameworks on top of this parsing system, using techniques such as EBNF grammars, but those experiments made the template engine too slow. It’s low-level because that’s fastest.

Writing the renderer ¶

The second step in writing custom tags is to define a Node subclass that has a render() method.

Continuing the above example, we need to define CurrentTimeNode :

  • __init__() gets the format_string from do_current_time() . Always pass any options/parameters/arguments to a Node via its __init__() .
  • The render() method is where the work actually happens.
  • render() should generally fail silently, particularly in a production environment where DEBUG and TEMPLATE_DEBUG are False . In some cases however, particularly if TEMPLATE_DEBUG is True , this method may raise an exception to make debugging easier. For example, several core tags raise django.template.TemplateSyntaxError if they receive the wrong number or type of arguments.

Ultimately, this decoupling of compilation and rendering results in an efficient template system, because a template can render multiple contexts without having to be parsed multiple times.

Auto-escaping considerations ¶

The output from template tags is not automatically run through the auto-escaping filters. However, there are still a couple of things you should keep in mind when writing a template tag.

If the render() function of your template stores the result in a context variable (rather than returning the result in a string), it should take care to call mark_safe() if appropriate. When the variable is ultimately rendered, it will be affected by the auto-escape setting in effect at the time, so content that should be safe from further escaping needs to be marked as such.

Also, if your template tag creates a new context for performing some sub-rendering, set the auto-escape attribute to the current context’s value. The __init__ method for the Context class takes a parameter called autoescape that you can use for this purpose. For example:

This is not a very common situation, but it’s useful if you’re rendering a template yourself. For example:

If we had neglected to pass in the current context.autoescape value to our new Context in this example, the results would have always been automatically escaped, which may not be the desired behavior if the template tag is used inside a {% autoescape off %} block.

Thread-safety considerations ¶

Once a node is parsed, its render method may be called any number of times. Since Django is sometimes run in multi-threaded environments, a single node may be simultaneously rendering with different contexts in response to two separate requests. Therefore, it’s important to make sure your template tags are thread safe.

To make sure your template tags are thread safe, you should never store state information on the node itself. For example, Django provides a builtin cycle template tag that cycles among a list of given strings each time it’s rendered:

A naive implementation of CycleNode might look something like this:

But, suppose we have two templates rendering the template snippet from above at the same time:

  • Thread 1 performs its first loop iteration, CycleNode.render() returns ‘row1’
  • Thread 2 performs its first loop iteration, CycleNode.render() returns ‘row2’
  • Thread 1 performs its second loop iteration, CycleNode.render() returns ‘row1’
  • Thread 2 performs its second loop iteration, CycleNode.render() returns ‘row2’

The CycleNode is iterating, but it’s iterating globally. As far as Thread 1 and Thread 2 are concerned, it’s always returning the same value. This is obviously not what we want!

To address this problem, Django provides a render_context that’s associated with the context of the template that is currently being rendered. The render_context behaves like a Python dictionary, and should be used to store Node state between invocations of the render method.

Let’s refactor our CycleNode implementation to use the render_context :

Note that it’s perfectly safe to store global information that will not change throughout the life of the Node as an attribute. In the case of CycleNode , the cyclevars argument doesn’t change after the Node is instantiated, so we don’t need to put it in the render_context . But state information that is specific to the template that is currently being rendered, like the current iteration of the CycleNode , should be stored in the render_context .

Notice how we used self to scope the CycleNode specific information within the render_context . There may be multiple CycleNodes in a given template, so we need to be careful not to clobber another node’s state information. The easiest way to do this is to always use self as the key into render_context . If you’re keeping track of several state variables, make render_context[self] a dictionary.

Registering the tag ¶

Finally, register the tag with your module’s Library instance, as explained in “Writing custom template filters” above. Example:

The tag() method takes two arguments:

  • The name of the template tag – a string. If this is left out, the name of the compilation function will be used.

As with filter registration, it is also possible to use this as a decorator:

If you leave off the name argument, as in the second example above, Django will use the function’s name as the tag name.

Passing template variables to the tag ¶

Although you can pass any number of arguments to a template tag using token.split_contents() , the arguments are all unpacked as string literals. A little more work is required in order to pass dynamic content (a template variable) to a template tag as an argument.

While the previous examples have formatted the current time into a string and returned the string, suppose you wanted to pass in a DateTimeField from an object and have the template tag format that date-time:

Initially, token.split_contents() will return three values:

  • The tag name format_time .
  • The string "blog_entry.date_updated" (without the surrounding quotes).
  • The formatting string "%Y-%m-%d %I:%M %p" . The return value from split_contents() will include the leading and trailing quotes for string literals like this.

Now your tag should begin to look like this:

You also have to change the renderer to retrieve the actual contents of the date_updated property of the blog_entry object. This can be accomplished by using the Variable() class in django.template .

To use the Variable class, simply instantiate it with the name of the variable to be resolved, and then call variable.resolve(context) . So, for example:

Variable resolution will throw a VariableDoesNotExist exception if it cannot resolve the string passed to it in the current context of the page.

Simple tags ¶

Many template tags take a number of arguments – strings or template variables – and return a string after doing some processing based solely on the input arguments and some external information. For example, the current_time tag we wrote above is of this variety: we give it a format string, it returns the time as a string.

To ease the creation of these types of tags, Django provides a helper function, simple_tag . This function, which is a method of django.template.Library , takes a function that accepts any number of arguments, wraps it in a render function and the other necessary bits mentioned above and registers it with the template system.

Our earlier current_time function could thus be written like this:

The decorator syntax also works:

A few things to note about the simple_tag helper function:

  • Checking for the required number of arguments, etc., has already been done by the time our function is called, so we don’t need to do that.
  • The quotes around the argument (if any) have already been stripped away, so we just receive a plain string.
  • If the argument was a template variable, our function is passed the current value of the variable, not the variable itself.

If your template tag needs to access the current context, you can use the takes_context argument when registering your tag:

Or, using decorator syntax:

For more information on how the takes_context option works, see the section on inclusion tags .

If you need to rename your tag, you can provide a custom name for it:

simple_tag functions may accept any number of positional or keyword arguments. For example:

Then in the template any number of arguments, separated by spaces, may be passed to the template tag. Like in Python, the values for keyword arguments are set using the equal sign (“ = ”) and must be provided after the positional arguments. For example:

Inclusion tags ¶

Another common type of template tag is the type that displays some data by rendering another template. For example, Django’s admin interface uses custom template tags to display the buttons along the bottom of the “add/change” form pages. Those buttons always look the same, but the link targets change depending on the object being edited – so they’re a perfect case for using a small template that is filled with details from the current object. (In the admin’s case, this is the submit_row tag.)

These sorts of tags are called “inclusion tags”.

Writing inclusion tags is probably best demonstrated by example. Let’s write a tag that outputs a list of choices for a given Poll object, such as was created in the tutorials . We’ll use the tag like this:

...and the output will be something like this:

First, define the function that takes the argument and produces a dictionary of data for the result. The important point here is we only need to return a dictionary, not anything more complex. This will be used as a template context for the template fragment. Example:

Next, create the template used to render the tag’s output. This template is a fixed feature of the tag: the tag writer specifies it, not the template designer. Following our example, the template is very simple:

Now, create and register the inclusion tag by calling the inclusion_tag() method on a Library object. Following our example, if the above template is in a file called results.html in a directory that’s searched by the template loader, we’d register the tag like this:

Alternatively it is possible to register the inclusion tag using a django.template.Template instance:

As always, decorator syntax works as well, so we could have written:

...when first creating the function.

Sometimes, your inclusion tags might require a large number of arguments, making it a pain for template authors to pass in all the arguments and remember their order. To solve this, Django provides a takes_context option for inclusion tags. If you specify takes_context in creating a template tag, the tag will have no required arguments, and the underlying Python function will have one argument – the template context as of when the tag was called.

For example, say you’re writing an inclusion tag that will always be used in a context that contains home_link and home_title variables that point back to the main page. Here’s what the Python function would look like:

(Note that the first parameter to the function must be called context .)

In that register.inclusion_tag() line, we specified takes_context=True and the name of the template. Here’s what the template link.html might look like:

Then, any time you want to use that custom tag, load its library and call it without any arguments, like so:

Note that when you’re using takes_context=True , there’s no need to pass arguments to the template tag. It automatically gets access to the context.

The takes_context parameter defaults to False . When it’s set to True , the tag is passed the context object, as in this example. That’s the only difference between this case and the previous inclusion_tag example.

inclusion_tag functions may accept any number of positional or keyword arguments. For example:

Setting a variable in the context ¶

The above examples simply output a value. Generally, it’s more flexible if your template tags set template variables instead of outputting values. That way, template authors can reuse the values that your template tags create.

To set a variable in the context, just use dictionary assignment on the context object in the render() method. Here’s an updated version of CurrentTimeNode that sets a template variable current_time instead of outputting it:

Note that render() returns the empty string. render() should always return string output. If all the template tag does is set a variable, render() should return the empty string.

Here’s how you’d use this new version of the tag:

Variable scope in context

Any variable set in the context will only be available in the same block of the template in which it was assigned. This behavior is intentional; it provides a scope for variables so that they don’t conflict with context in other blocks.

But, there’s a problem with CurrentTimeNode2 : The variable name current_time is hard-coded. This means you’ll need to make sure your template doesn’t use {{ current_time }} anywhere else, because the {% current_time %} will blindly overwrite that variable’s value. A cleaner solution is to make the template tag specify the name of the output variable, like so:

To do that, you’ll need to refactor both the compilation function and Node class, like so:

The difference here is that do_current_time() grabs the format string and the variable name, passing both to CurrentTimeNode3 .

Finally, if you only need to have a simple syntax for your custom context-updating template tag, you might want to consider using an assignment tag .

Assignment tags ¶

To ease the creation of tags setting a variable in the context, Django provides a helper function, assignment_tag . This function works the same way as simple_tag , except that it stores the tag’s result in a specified context variable instead of directly outputting it.

You may then store the result in a template variable using the as argument followed by the variable name, and output it yourself where you see fit:

assignment_tag functions may accept any number of positional or keyword arguments. For example:

Parsing until another block tag ¶

Template tags can work in tandem. For instance, the standard {% comment %} tag hides everything until {% endcomment %} . To create a template tag such as this, use parser.parse() in your compilation function.

Here’s how a simplified {% comment %} tag might be implemented:

The actual implementation of {% comment %} is slightly different in that it allows broken template tags to appear between {% comment %} and {% endcomment %} . It does so by calling parser.skip_past('endcomment') instead of parser.parse(('endcomment',)) followed by parser.delete_first_token() , thus avoiding the generation of a node list.

parser.parse() takes a tuple of names of block tags ‘’to parse until’‘. It returns an instance of django.template.NodeList , which is a list of all Node objects that the parser encountered ‘’before’’ it encountered any of the tags named in the tuple.

In "nodelist = parser.parse(('endcomment',))" in the above example, nodelist is a list of all nodes between the {% comment %} and {% endcomment %} , not counting {% comment %} and {% endcomment %} themselves.

After parser.parse() is called, the parser hasn’t yet “consumed” the {% endcomment %} tag, so the code needs to explicitly call parser.delete_first_token() .

CommentNode.render() simply returns an empty string. Anything between {% comment %} and {% endcomment %} is ignored.

Parsing until another block tag, and saving contents ¶

In the previous example, do_comment() discarded everything between {% comment %} and {% endcomment %} . Instead of doing that, it’s possible to do something with the code between block tags.

For example, here’s a custom template tag, {% upper %} , that capitalizes everything between itself and {% endupper %} .

As in the previous example, we’ll use parser.parse() . But this time, we pass the resulting nodelist to the Node :

The only new concept here is the self.nodelist.render(context) in UpperNode.render() .

For more examples of complex rendering, see the source code for {% if %} , {% for %} , {% ifequal %} or {% ifchanged %} . They live in django/template/defaulttags.py .

Table Of Contents

  • Code layout
  • Registering custom filters
  • Template filters that expect strings
  • Filters and auto-escaping
  • Filters and time zones
  • A quick overview
  • Writing the compilation function
  • Writing the renderer
  • Auto-escaping considerations
  • Thread-safety considerations
  • Registering the tag
  • Passing template variables to the tag
  • Simple tags
  • Inclusion tags
  • Setting a variable in the context
  • Assignment tags
  • Parsing until another block tag
  • Parsing until another block tag, and saving contents
  • Prev: Writing custom model fields
  • Next: Writing a custom storage system

You are here:

  • Custom template tags and filters
  • Show Source

Quick search

Enter search terms or a module, class or function name.

Last update:

Mar 09, 2014

  • Docker Security
  • DotNet Security
  • Error Handling
  • File Upload
  • Forgot Password
  • HTML5 Security
  • HTTP Headers
  • HTTP Strict Transport Security
  • Infrastructure as Code Security
  • Injection Prevention
  • Injection Prevention in Java
  • Input Validation
  • Insecure Direct Object Reference Prevention
  • JSON Web Token for Java
  • Java Security
  • Key Management
  • Kubernetes Security
  • LDAP Injection Prevention
  • Logging Vocabulary
  • Mass Assignment
  • Microservices Security
  • Microservices based Security Arch Doc
  • Mobile Application Security
  • Multifactor Authentication
  • NPM Security
  • Network Segmentation
  • NodeJS Docker
  • Nodejs Security
  • OS Command Injection Defense
  • PHP Configuration
  • Password Storage
  • Prototype Pollution Prevention
  • Query Parameterization
  • REST Assessment
  • REST Security
  • Ruby on Rails
  • SAML Security
  • SQL Injection Prevention
  • Secrets Management
  • Secure Cloud Architecture
  • Secure Product Design
  • Securing Cascading Style Sheets
  • Server Side Request Forgery Prevention
  • Session Management
  • Software Supply Chain Security.md
  • TLS Cipher String
  • Third Party Javascript Management
  • Threat Modeling
  • Transaction Authorization
  • Transport Layer Protection
  • Transport Layer Security
  • Unvalidated Redirects and Forwards
  • User Privacy Protection
  • Virtual Patching
  • Vulnerability Disclosure
  • Vulnerable Dependency Management
  • Web Service Security
  • XML External Entity Prevention
  • XML Security
  • XSS Filter Evasion

Django Security Cheat Sheet ¶

Introduction ¶.

The Django framework is a powerful Python web framework, and it comes with built-in security features that can be used out-of-the-box to prevent common web vulnerabilities. This cheat sheet lists actions and security tips developers can take to develop secure Django applications. It aims to cover common vulnerabilities to increase the security posture of your Django application. Each item has a brief explanation and relevant code samples that are specific to the Django environment.

The Django framework provides some built-in security features that aim to be secure-by-default. These features are also flexible to empower a developer to re-use components for complex use-cases. This opens up scenarios where developers unfamiliar with the inner workings of the components can configure them in an insecure way. This cheat sheet aims to enumerate some such use cases.

General Recommendations ¶

  • Always keep Django and your application's dependencies up-to-date to keep up with security vulnerabilities.
  • Ensure that the application is never in DEBUG mode in a production environment. Never run DEBUG = True in production.
  • Use packages like django_ratelimit or django-axes to prevent brute-force attacks.

Authentication ¶

  • Use django.contrib.auth app for views and forms for user authentication operations such as login, logout, password change, etc. Include the module and its dependencies django.contrib.contenttypes and django.contrib.sessions in the INSTALLED_APPS setting in the settings.py file.
  • Use the @login_required decorator to ensure that only authenticated users can access a view. The sample code below illustrates usage of @login_required .
  • Use password validators for enforcing password policies. Add or update the AUTH_PASSWORD_VALIDATORS setting in the settings.py file to include specific validators required by your application.
  • Store passwords using make-password utility function to hash a plain-text password.
  • Check a plaintext password against a hashed password by using the check-password utility function.

Key Management ¶

The SECRET_KEY parameter in settings.py is used for cryptographic signing and should be kept confidential. Consider the following recommendations:

  • Generate a key at least 50 characters or more, containing a mix of letters, digits, and symbols.
  • Ensure that the SECRET_KEY is generated using a strong random generator, such as get_random_secret_key() function in Django.
  • Avoid hard coding the SECRET_KEY value in settings.py or any other location. Consider storing the key-value in environment variables or secrets managers.
  • Regularly rotate the key, keeping in mind that this action can invalidate sessions, password reset tokens, etc. Rotate the key immediatley it if it ever gets exposed.

Headers ¶

Include the django.middleware.security.SecurityMiddleware module in the MIDDLEWARE setting in your project's settings.py to add security-related headers to your responses. This module is used to set the following parameters:

  • SECURE_CONTENT_TYPE_NOSNIFF : Set this key to True . Protects against MIME type sniffing attacks by enabling the header X-Content-Type-Options: nosniff .
  • SECURE_BROWSER_XSS_FILTER : Set this key to True . Enables the browser’s XSS filter by setting the header X-XSS-Protection: 1; mode=block .
  • SECURE_HSTS_SECONDS : Ensures the site is only accessible via HTTPS.

Include the django.middleware.clickjacking.XFrameOptionsMiddleware module in the MIDDLEWARE setting in your project's settings.py (This module should be listed after the django.middleware.security.SecurityMiddleware module as ordering is important). This module is used to set the following parameters:

  • X_FRAME_OPTIONS : Set this key to to 'DENY' or 'SAMEORIGIN'. This setting adds the X-Frame-Options header to all HTTP responses. This protects against clickjacking attacks.

Cookies ¶

  • SESSION_COOKIE_SECURE : Set this key to True in the settings.py file. This will send the session cookie over secure (HTTPS) connections only.
  • CSRF_COOKIE_SECURE : Set this key to True in the settings.py file. This will ensure that the CSRF cookie is sent over secure connections only.
  • Whenever you set a custom cookie in a view using the HttpResponse.set_cookie() method, make sure to set its secure parameter to True .

Cross Site Request Forgery (CSRF) ¶

  • Include the django.middleware.csrf.CsrfViewMiddleware module in the MIDDLEWARE setting in your project's settings.py to add CSRF related headers to your responses.
  • In forms use the {% csrf_token %} template tag to include the CSRF token. A sample is shown below.
  • For AJAX calls, the CSRF token for the request has to be extracted prior to being used in the the AJAX call.
  • Additional recommendations and controls can be found at Django's Cross Site Request Forgery protection documentation.

Cross Site Scripting (XSS) ¶

The recommendations in this section are in addition to XSS recommendations already mentioned previously.

  • Use the built-in template system to render templates in Django. Refer to Django's Automatic HTML escaping documentation to learn more.
  • Avoid using safe , mark_safe , or json_script filters for disabling Django's automatic template escaping. The equivalent function in Python is the make_safe() function. Refer to the json_script template filter documentation to learn more.
  • Refer to Django's Cross Site Scripting (XSS) protection documentation to learn more.

HTTPS ¶

  • Include the django.middleware.security.SecurityMiddleware module in the MIDDLEWARE setting in your project's settings.py if not already added.
  • Set the SECURE_SSL_REDIRECT = True in the settings.py file to ensure that all communication is over HTTPS. This will redirect any HTTP requests automatically to HTTPS. This is also a 301 (permanent) redirect, so your browser will remember the redirect for subsequent requests.
  • If your Django application is behind a proxy or load balancer, set the SECURE_PROXY_SSL_HEADER setting to TRUE so that Django can detect the original request's protocol. For futher details refer to SECURE_PROXY_SSL_HEADER documentation .

Admin panel URL ¶

It is advisable to modify the default URL leading to the admin panel (example.com/admin/), in order to slightly increase the difficulty for automated attacks. Here’s how to do it:

In the default app folder within your project, locate the urls.py file managing the top-level URLs. Within the file, modify the urlpatterns variable, a list, so that the URL leading to admin.site.urls is different from "admin/". This approach adds an extra layer of security by obscuring the common endpoint used for administrative access.

References ¶

Additional documentation -

  • Clickjacking Protection
  • Security Middleware
  • Stack Overflow Public questions & answers
  • Stack Overflow for Teams Where developers & technologists share private knowledge with coworkers
  • Talent Build your employer brand
  • Advertising Reach developers & technologists worldwide
  • Labs The future of collective knowledge sharing
  • About the company

Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Get early access and see previews of new features.

Django messages showing up for unknown reasons

Now I am trying to build messaging functionality into my webapp, where businesses can message buyers and users can message sellers.

The messaging functionality works fine, but the problem is, debug django messages show up such as Message from john to steve in Lululemon , I don't even know where they are coming from, which view is causing them.

Maybe because I am using Django Messages Framework, when I call the messages.add_message function or use the contrib.messages context processor in my views, Django adds these messages to the request context. These messages are then being displayed in my base template wherever I have included the {% if messages %} block.

Now I don't know how to get rid of these messages for this view.

My models.py:

My views.py:

My urls.py:

I even tried using a context_processor to get rid of django messages for this view only, but did not work:

  • django-models
  • django-views
  • django-messages

Jack's user avatar

Know someone who can answer? Share a link to this question via email , Twitter , or Facebook .

Your answer.

Reminder: Answers generated by artificial intelligence tools are not allowed on Stack Overflow. Learn more

Sign up or log in

Post as a guest.

Required, but never shown

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy .

Browse other questions tagged django django-models django-views django-messages or ask your own question .

  • The Overflow Blog
  • Introducing Staging Ground: The private space to get feedback on questions...
  • Featured on Meta
  • The return of Staging Ground to Stack Overflow
  • The [tax] tag is being burninated
  • The 2024 Developer Survey Is Live
  • Policy: Generative AI (e.g., ChatGPT) is banned

Hot Network Questions

  • Does a Buddha have an "awareness" separate from the five aggregates?
  • Estimating Probability Density for Sample
  • What does "however" mean in this sentence? Does it mean ''still'' or "moreover"?
  • Can LLMs have intention?
  • How do you keep the horror spooky when your players are a bunch of goofballs?
  • A trigonometric equation: how hard could it be?
  • What's the maximum amount of material that a puzzle with unique solution can have?
  • Has ever a country by its own volition refused to join United Nations, or those which havent joined it's because they aren't recognized as such by UN?
  • Transformer with same size symbol meaning
  • "Mandatory reservation" on Off-Peak ticket?
  • What should I get paid for if I can't work due to circumstances outside of my control?
  • Romans 3:22 – ‘of’ or ‘in’? Old translations differ from modern ones. Why?
  • Quick release inside of thru axle?
  • How often does systemd journal collect/read logs from sources
  • What terminal did David connect to his IMSAI 8080?
  • NES Emulator in C
  • Converting NEMA 10-30 to 14-30 using ground from adjacent 15 amp receptacle
  • Why does this arc die in the center?
  • Inductance after core saturation
  • Can I paraphrase an conference paper I wrote in my dissertation?
  • Is the barrier to entry for mathematics research increasing, and is it at risk of becoming less accessible in the future?
  • Under physicalism, should I still be sad if my murdered wife is replaced with a perfect clone?
  • Connecting to very old Linux OS with ssh
  • Is 1.5 hours enough for flight transfer in Frankfurt?

django assignment_tag

COMMENTS

  1. How to create custom template tags and filters

    To define a custom template tag, you specify how the compilation works and how the rendering works. When Django compiles a template, it splits the raw template text into ''nodes''. Each node is an instance of django.template.Node and has a render() method. A compiled template is a list of Node objects.

  2. django

    Create a template tag: The app should contain a templatetags directory, at the same level as models.py, views.py, etc.If this doesn't already exist, create it - don't forget the __init__.py file to ensure the directory is treated as a Python package.. Create a file named define_action.py inside of the templatetags directory with the following code: ...

  3. Extend Django Templates with Custom Tags and Filters

    This guide covers how to create and use custom template tags and filters to enhance the template rendering process in Django. Below is a detailed explanation of the different types of template tags in Django: 1. Simple Tags Simple tags are used to generate content dynamically within a template.

  4. Django Templates: Implementing Custom Tags and Filters

    Custom tags and filters live in your Django app in a templatetags/ directory. You can import any files in this directory into a template using the {% load %} tag. The name of the module you create will be the name you use to load the tag library. For this project, the structure will look like this:

  5. Understanding and Implementing Custom Template Tags in Django

    Simple template tags and inclusion tags cover the majority of use cases for custom template tags. However, Django offers advanced template tags for more customization. These tags consist of two parts: A parser function: Called when its template tag is encountered in a template. It parses the template tag and extracts variables from the context.

  6. How to create Custom Template Tags in Django

    Django provides the following helper functions that allow you to create your own template tags in an easy manner: simple_tag: Processes the data and returns a string; inclusion_tag: Processes the data and returns a rendered template; assignment_tag: Processes the data and sets a variable in the context; Explanation:

  7. Custom template tags in Django

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

  8. Creating Custom Template Tags In Django Application

    Assignment tags are like simple tags but they store the result in a given variable. Edit the custom_tags.py file and add the following import and template tag in it: @register.assignment_tag def any_function(count=5): return *some database query* The notation for assignment template tags is {% template_tag as variable %}. We can use assignment ...

  9. Django Custom Template Tags And Filters

    Defining own Custom Template Tags: In Your app_tags.py. from django import template. register = template.Library() @register.assignment_tag def get_result_tag ( arg1, arg2, arg3 ): "----" return "response". register = template.Library (): This refers that you need to make sure, your templates are added to the existing library of tags and ...

  10. Create Custom Template Tags in Django: A complete guide

    How to create a simple_tag in Django? Here are the steps to create a simple tag in Django: Import the necessary modules including django.template; Instantiate django.template.Library and assign it to the variable, register. Define the custom template tag function providing the necessary arguments, desired logic, and the return data.

  11. Creating Custom Template Tags In Django Application

    Assignment tags are like simple tags but they store the result in a given variable. Edit the custom_tags.py file and add the following import and template tag in it: @register.assignment_tag def ...

  12. django

    Using the Django assignment_tag built-in tag the right way. 5. Django Template Tag Conditional. 3. Django custom assignment_tag does not get executed. 19. Python Django custom template tags register.assignment_tag not working. 2. Django Template Tag With No Arguments. 1.

  13. Custom template tags and filters

    Custom template tags and filters¶. Django's template language comes with a wide variety of built-in tags and filters designed to address the presentation logic needs of your application. Nevertheless, you may find yourself needing functionality that is not covered by the core set of template primitives.

  14. Django Template Variables

    Create Variable in View. The variable firstname in the example above was sent to the template via a view: from django.template import loader. template = loader.get_template('template.html') context = { 'firstname': 'Linus', } return HttpResponse(template.render(context, request)) As you can see in the view above, we create an object named ...

  15. Using Custom Tags to Display Dashboard in Django Admin

    Our tags should be set up inside the folder templatetags we've prepared before. There are three types of custom tags supported by Django: simple tag, inclusion tag, and assignment tag. We'll ...

  16. python

    1. Firstly, that's not how assignment tags work. You have never actually called the tag; if partner refers to a (non-existent) template variable named "partner". You call an assignment tag by using it on its own along with a variable to assign it to: {% partner as partner_value %} {% if partner_value %}...{% endif %}

  17. Custom template tags and filters

    To define a custom template tag, you specify how the compilation works and how the rendering works. When Django compiles a template, it splits the raw template text into ''nodes''. Each node is an instance of django.template.Node and has a render () method. A compiled template is, simply, a list of Node objects.

  18. Django Security

    Introduction. The Django framework is a powerful Python web framework, and it comes with built-in security features that can be used out-of-the-box to prevent common web vulnerabilities. This cheat sheet lists actions and security tips developers can take to develop secure Django applications. It aims to cover common vulnerabilities to increase ...

  19. Django simple_tag and setting context variables

    You are mixing two approaches here. A simple_tag is merely a helper function, which cuts down on some boilerplate code and is supposed to return a string. To set context variables, you need (at least with plain django) to write your own tag with a render method.. from django import template register = template.Library() class FooNode(template.Node): def __init__(self, obj): # saves the passed ...

  20. how to do assignments for variable in django template tag

    If your template logic is too simple then the answer below (using the with template tag) may help you. Otherwise, Jinja 2 is the only solution. Otherwise, Jinja 2 is the only solution. Nevertheless, try, if you can, to put such logic inside your views.py to avoid such scenarios.

  21. Django messages showing up for unknown reasons

    Now I am trying to build messaging functionality into my webapp, where businesses can message buyers and users can message sellers. The messaging functionality works fine, but the problem is, debug django messages show up such as Message from john to steve in Lululemon, I don't even know where they are coming from, which view is causing them.. Maybe because I am using Django Messages Framework ...