@register.filter vs @register.simple_tag vs @register.tag vs @register.inclusion_tag in Django Templates

737 Views Asked by At

The doc says about @register.filter below:

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.

And, the doc says about @register.simple_tag below:

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.

And, the doc only says about @register.tag below:

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

And, the doc says about @register.inclusion_tag below:

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.

But, I don't understand what they are like so what is the difference between @register.filter @register.simple_tag, @register.tag and @register.inclusion_tag in Django Templates?

1

There are 1 best solutions below

0
Super Kai - Kazuya Ito On

@register.filter:

  • can return data to Django Templates.
  • 's function can get the values from the template tag.
  • 's function must have one or two parameters. *If it has zero or more than two parameters, there is error.
  • cannot have takes_context parameter.
  • doesn't work with as argument.

@register.simple_tag:

  • can return data to Django Templates.
  • 's function can get the values from the template tag.
  • can have takes_context parameter.
  • 's function must have context as the 1st parameter if takes_context=True is set to @register.simple_tag otherwise there is an error. *The 1st parameter name must be context otherwise there is an error.
  • works with as argument.

@register.tag:

  • should return a str type value from a Node class based object to Django Templates otherwise there is an error.
  • 's function can get the tokens from the template tag.
  • cannot have takes_context parameter.
  • 's function must have parser as the 1st parameter and token as the 2nd parameter in convention (other names are fine) otherwise there is an error.
  • doesn't work with as argument.

@register.inclusion_tag:

  • can return data to other Django Templates but not to the same Django Templates because there is an error.
  • 's function can get the values from the template tag.
  • can have takes_context parameter.
  • 's function must have context as the 1st parameter if takes_context=True is set to @register.inclusion_tag otherwise there is an error. *The 1st parameter name must be context otherwise there is an error.
  • doesn't work with as argument.

<@register.filter>

For example, return a dictionary to index.html from person_view() as shown below:

# "views.py"

from django.shortcuts import render

def person_view(request):                # Dictionary
    return render(request, 'index.html', {'name':'John', 'age': 36})

Then, pass name to person_filter() as shown below:

# "index.html"

{% load custom_tags %}

{{ name | person }}

Then, return name from person_filter() to index.html as shown below:

# "custom_tags.py"

from django.template import Library

register = Library()

@register.filter(name="person")
def person_filter(name):
    return name

Then, this below is displayed:

John

Next, pass name and age to person_filter() as shown below:

# "index.html"

{% load custom_tags %}

{{ name | person:age }}

Then, return name and age from person_filter() to index.html as shown below:

# "custom_tags.py"

from django.template import Library

register = Library()

@register.filter(name="person")
def person_filter(name, age):
    return f'{name} {age}'

Then, this below is displayed:

John 36

<@register.simple_tag>

For example, return a dictionary to index.html from person_view() as shown below:

# "views.py"

from django.shortcuts import render

def person_view(request):                # Dictionary
    return render(request, 'index.html', {'name':'John', 'age': 36})

Then, pass name, age and "Good Person" to person_tag() as shown below:

# "index.html"

{% load custom_tags %}

{% person name age "Good Person" %}

Then, return name, age and extra_info from person_tag() to index.html as shown below:

# "custom_tags.py"

from django.template import Library

register = Library()

@register.simple_tag(name="person")
def person_tag(name, age, extra_info):
    return f'{name} {age} {extra_info}'

Then, this below is displayed:

John 36 Good Person

Next, set takes_context=True to @register.simple_tag, then for person_tag(), we don't need name and age parameters, then must put context which is a dictionary as the 1st parameter as shown below. *If the 1st parameter name is not context, there is an error:

# "custom_tags.py"
                                    # Here
@register.simple_tag(name="person", takes_context=True)
def person_tag(context, extra_info):
    return f"{context['name']} {context['age']} {extra_info}"

Then, pass only "Good Person" to person_tag() as shown below:

# "index.html"

{% person "Good Person" %}

Then, this below is displayed:

John 36 Good Person

Actually, you can still pass name and age from index.html to person_tag() as shown below:

# "index.html"

{% person name age "Good Person" %}

But, person_tag() needs 2 more parameters as shown below. *Other names are fine for name and age parameters:

# "custom_tags.py"

@register.simple_tag(name="person", takes_context=True)
def person_tag(context, name, age, extra_info):
    # ...                 ↑    ↑

Next, store the return values from person_tag() to person_info with as argument, then display it as shown below. *The tag with as argument is not displayed:

# "index.html"

{% person "Good Person" as person_info %}
{{ person_info }}

Then, this below is displayed:

John 36 Good Person

Lastly in person_tag(), set context['extra_info'], then return an empty string to index.html as shown below:

# "custom_tags.py"

@register.simple_tag(name="person", takes_context=True)
def person_tag(context, extra_info):
    context['extra_info'] = extra_info
    return ""

Then, display name, age and extra_info as shown below:

# "index.html"

{% person "Good Person" %}
{{ name }} {{ age }} {{ extra_info }}

Then, this below is displayed:

John 36 Good Person

<@register.tag>

For example, return a dictionary to index.html from person_view() as shown below:

# "views.py"

from django.shortcuts import render

def person_view(request):                # Dictionary
    return render(request, 'index.html', {'name':'John', 'age': 36})

Then, pass name, age and "Good Person" to person_tag() as shown below:

# "index.html"

{% load custom_tags %}

{% person name age "Good Person" %}

Then from person_tag(), return PersonNode() which returns 4 tokens from render() to index.html as shown below. *The 1st token is the tag name person and the 2nd token is name and the 3rd token is age and the 4th token is "Good Person" and @register.tag cannot have takes_context parameter and @register.tag's function must have parser as the 1st parameter and token as the 2nd parameter in convention (other names are fine) otherwise there is an error:

# "custom_tags.py"

from django.template import Library, Node

register = Library()

@register.tag(name="person")
def person_tag(parser, token):
    token0, token1, token2, token3 = token.split_contents()
    return PersonNode(token0, token1, token2, token3)

class PersonNode(Node):
    def __init__(self, token0, token1, token2, token3):
        self.token0 = token0
        self.token1 = token1
        self.token2 = token2
        self.token3 = token3

    def render(self, context):
        return f'{self.token0} {self.token1} {self.token2} {self.token3}'

Then, this below is displayed:

person name age "Good Person"

And, this code below returns the 1st token, the actual name and age values got by the 2nd and 3rd tokens respectively and the 4th token without double quotes. *template.Variable("key.dot.notation").resolve(dict) can get the value from a dictionary with a key dot notation and you can see my answer explaining template.Variable("key.dot.notation").resolve(dict):

# "custom_tags.py"

@register.tag(name="person")
def person_tag(parser, token):
    token0, token1, token2, token3 = token.split_contents()
    return PersonNode(token0, token1, token2, token3)

class PersonNode(Node):
    def __init__(self, token0, token1, token2, token3):
        self.token0 = token0
        self.token1 = token1
        self.token2 = token2
        self.token3 = token3

    def render(self, context):
        name = template.Variable(self.token1).resolve(context)
        age = template.Variable(self.token2).resolve(context)
        extra_info = self.token3.replace('"', '')
        return f'{self.token0} {name} {age} {extra_info}'

Then, this below is displayed:

person John 36 Good Person

And, this code below returns name and age values from context and Good Person:

# "custom_tags.py"

@register.tag(name="person")
def person_tag(parser, token):
    token0, token1, token2, token3 = token.split_contents()
    return PersonNode()

class PersonNode(Node):
    def render(self, context):
        return f"{context['name']} {context['age']} Good Person"

Then, this below is displayed:

John 36 Good Person

And in render(), set context['extra_info'], then return an empty string to index.html as shown below:

# "custom_tags.py"

@register.tag(name="person")
def person_tag(parser, token):
    return PersonNode()

class PersonNode(Node):
    def render(self, context):
        context['extra_info'] = "Good Person"
        return ""

Then, display name, age and extra_info as shown below:

# "index.html"

{% person %}
{{ name }} {{ age }} {{ extra_info }}

Then, this below is displayed:

John 36 Good Person

In addition, we can create a comment tag to comment words with parser parameter and @register.tag as shown below:

# "custom_tags.py"

@register.tag(name='comm')
def comment_tag(parser, token):
    parser.skip_past('endcomm')
    return CommentNode()

class CommentNode(Node):
    def render(self, context):
        return ""

Then, surround the words with the comment tag {% comm %} and {% endcomm %} not to display the words as shown below:

# "index.html"

{% comm %}This is a comment.{% endcomm %}

<@register.inclusion_tag>

For example, return a dictionary to index.html from person_view() as shown below:

# "views.py"

from django.shortcuts import render

def person_view(request):                # Dictionary
    return render(request, 'index.html', {'name':'John', 'age': 36})

Then, pass name, age and "Good Person" to person_tag() as shown below:

# "index.html"

{% load custom_tags %}

{% person name age "Good Person" %}

Then, return a dictionary from person_tag() to result.html as shown below:

# "custom_tags.py"

from django.template import Library

register = Library()

@register.inclusion_tag(name='person', filename='result.html')
def person_tag(name, age, extra_info):
    return {'n': name, 'a': age, 'ei': extra_info} # Dictionary

Then, display n, a and ei in result.html as shown below:

# "result.html"

{{ n }} {{ a }} {{ ei }}

Then, this below is displayed:

John 36 Good Person

Be careful, name, age and extra_info below cannot be displayed in result.html because they are not returned from person_tag() to result.html:

# "result.html"

{{ name }} {{ age }} {{ extra_info }}

Next, set takes_context=True to @register.inclusion_tag, then for person_tag(), we don't need name and age parameters, then must put context which is a dictionary as the 1st parameter, then set context['extra_info'] as shown below. *If the 1st parameter name is not context, there is an error:

# "custom_tags.py"

@register.inclusion_tag(
    name='person', 
    filename='result.html', 
    takes_context=True
)
def person_tag(context, extra_info):
    context['extra_info'] = extra_info
    return context

Then, pass only "Good Person" to person_tag() as shown below:

# "index.html"

{% person "Good Person" %}

Then, display name, age and extra_info in result.html as shown below:

# "result.html"

{{ name }} {{ age }} {{ extra_info }}

Then, this below is displayed:

John 36 Good Person

Actually, you can still pass name and age from index.html to person_tag() as shown below:

# "index.html"

{% person name age "Good Person" %}

But, person_tag() needs 2 more parameters as shown below. *Other names are fine for name and age parameters:

# "custom_tags.py"

@register.inclusion_tag(
    name='person', 
    filename='result.html', 
    takes_context=True
)
def person_tag(context, name, age, extra_info):
    # ...                 ↑    ↑

Lastly, return an empty dictionary from person_tag() to result.html as shown below:

# "custom_tags.py"

@register.inclusion_tag(
    name='person', 
    filename='result.html', 
    takes_context=True
)
def person_tag(context, extra_info):
    context['extra_info'] = extra_info
    return {} # Dictionary

Then, display name, age and extra_info in index.html as shown below:

# "index.html"

{% person "Good Person" %}
{{ name }} {{ age }} {{ extra_info }}

Then, this below is displayed:

John 36 Good Person