A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://django-components.github.io/django-components/latest/concepts/advanced/template_tags/ below:

Custom template tags - Django-Components

Custom template tags

Template tags introduced by django-components, such as {% component %} and {% slot %}, offer additional features over the default Django template tags:

You too can easily create custom template tags that use the above features.

The simplest way to create a custom template tag is using the template_tag decorator. This decorator allows you to define a template tag by just writing a function that returns the rendered content.

from django.template import Context, Library
from django_components import BaseNode, template_tag

library = Library()

@template_tag(
    library,
    tag="mytag",
    end_tag="endmytag",
    allowed_flags=["required"]
)
def mytag(node: BaseNode, context: Context, name: str, **kwargs) -> str:
    return f"Hello, {name}!"

This will allow you to use the tag in your templates like this:

{% mytag name="John" %}
{% endmytag %}

{# or with self-closing syntax #}
{% mytag name="John" / %}

{# or with flags #}
{% mytag name="John" required %}
{% endmytag %}
Parameters¤

The @template_tag decorator accepts the following parameters:

Function signature¤

The function decorated with @template_tag must accept at least two arguments:

  1. node: The node instance (we'll explain this in detail in the next section)
  2. context: The Django template context

Any additional parameters in your function's signature define what inputs your template tag accepts. For example:

@template_tag(library, tag="greet")
def greet(
    node: BaseNode,
    context: Context,
    name: str,                    # required positional argument
    count: int = 1,              # optional positional argument
    *,                           # keyword-only arguments marker
    msg: str,                    # required keyword argument
    mode: str = "default",       # optional keyword argument
) -> str:
    return f"{msg}, {name}!" * count

This allows the tag to be used like:

{# All parameters #}
{% greet "John" count=2 msg="Hello" mode="custom" %}

{# Only required parameters #}
{% greet "John" msg="Hello" %}

{# Missing required parameter - will raise error #}
{% greet "John" %}  {# Error: missing 'msg' #}

When you pass input to a template tag, it behaves the same way as if you passed the input to a function:

To accept keys that are not valid Python identifiers (e.g. data-id), or would conflict with Python keywords (e.g. is), you can use the **kwargs syntax:

@template_tag(library, tag="greet")
def greet(
    node: BaseNode,
    context: Context,
    **kwargs,
) -> str:
    attrs = kwargs.copy()
    is_var = attrs.pop("is", None)
    attrs_str = " ".join(f'{k}="{v}"' for k, v in attrs.items())

    return mark_safe(f"""
        <div {attrs_str}>
            Hello, {is_var}!
        </div>
    """)

This allows you to use the tag like this:

{% greet is="John" data-id="123" %}

For more control over your template tag, you can subclass BaseNode directly instead of using the decorator. This gives you access to additional features like the node's internal state and parsing details.

from django_components import BaseNode

class GreetNode(BaseNode):
    tag = "greet"
    end_tag = "endgreet"
    allowed_flags = ["required"]

    def render(self, context: Context, name: str, **kwargs) -> str:
        # Access node properties
        if self.flags["required"]:
            return f"Required greeting: Hello, {name}!"
        return f"Hello, {name}!"

# Register the node
GreetNode.register(library)
Node properties¤

When using BaseNode, you have access to several useful properties:

This is what the node parameter in the @template_tag decorator gives you access to - it's the instance of the node class that was automatically created for your template tag.

Rendering content between tags¤

When your tag has an end tag, you can access and render the content between the tags using nodelist:

class WrapNode(BaseNode):
    tag = "wrap"
    end_tag = "endwrap"

    def render(self, context: Context, tag: str = "div", **attrs) -> str:
        # Render the content between tags
        inner = self.nodelist.render(context)
        attrs_str = " ".join(f'{k}="{v}"' for k, v in attrs.items())
        return f"<{tag} {attrs_str}>{inner}</{tag}>"

# Usage:
{% wrap tag="section" class="content" %}
    Hello, world!
{% endwrap %}
Unregistering nodes¤

You can unregister a node from a library using the unregister method:

GreetNode.unregister(library)

This is particularly useful in testing when you want to clean up after registering temporary tags.

2025-06-03 Juro Oravec

RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4