Evgenii Legotckoi
Evgenii LegotckoiMarch 21, 2023, 4:17 a.m.

Django - Lesson 062. How to write a block-template tabbar tag like the blocktranslate tag

In this article, I'll show you exactly how you can write a simple block template tag, like the blocktranslate tag in Django .

These block template tags have an opening tag and a closing tag, and the most common one I would call the blocktranslate tag, which allows you to translate entire pieces of html code, not just individual sentences. The tag will look like this:

{% blocktranslate %}This string will have {{ value }} inside.{% endblocktranslate %}

In this case, the tag has a blocktranslate opening tag and an endblocktranslate closing tag, and the content inside is being manipulated.

Personally, I wrote a few simple tags for myself to simplify writing template code on the site. One such tag is the tabber tag inside which I also use tab_item tags.

This reduces coding in templates and makes the template friendlier and easier to maintain.

As a result, my template code may look like this.

{% load tabbar tab_item from myapp %}

{% url 'myapp:settings_main' as the_settings_main_url %}
{% url 'myapp:settings_notification' as the_settings_notification_url %}

{% tabbar %}
  {% tab_item _('Main') the_settings_main_url True %}
  {% tab_item _('Notifications') the_settings_notification_url %}
{% end_tabbar %}

As a result, these template tags generate the following html code

<div class="overflow-hidden">
  <div class="nav nav-tabs border-bottom flex-nowrap">
    <a class="text-nowrap nav-item nav-link active" href="/ru/myapp/settings/main/">Основное</a>
    <a class="text-nowrap nav-item nav-link" href="/ru/myapp/settings/notification/">Уведомления</a>

As you can see, quite standard bootstrap Tab Bar code is generated here.

And if this particular case may not be something that may require writing such a tag, then knowing how to write such a tag can come in handy in more complex layouts, or where there are many places on the site where such tabs are used. Which will be very useful, since in order to change the layout in all parts of the site, it will be enough to change only the code of these template tags.

Now let's start learning how to write such a template tag.

Application structure

Let's say we have an application myapp that will contain these template tags. This requires that directories and files with the following structure be created in this application (in addition to those that are created by default)

  • myapp
    • templates
      • myapp
        • tabbar.html
        • tab_item.html
    • templatetages
      • __init__.py
      • myapp.py

tabbar tag in myapp.py file

This file will contain the python code for processing the tag in the template, and next to it is the init .py file, which initializes myapp in the templatetags directory as a tag library. By default, this file is empty, but it is needed there.

Let's start by adding the necessary imports.

# -*- coding: utf-8 -*-

import random

from django import template
from django.template.loader import render_to_string
from django.utils.translation import ugettext_lazy as _

register = template.Library()

Then we will register the template tag. The important point is that usually functions that are registered as a block template tag start with the do_ prefix. As you can see in the code below, as soon as the Django parser finds the {% tabbar %} tag, it immediately starts parsing the template in the form of a list of nodes, then the closing tag, which in this case is named end_tabbar , while the first token from the parser is removed. As I understand it, the node inside which the tabbar tag was found is deleted, as a result, it is no longer processed. The list of nodes is passed to the custom node class ( TabBarNode ) for further processing.

def do_tabbar(parser, token):
    tag_name, args, kwargs = parse_tag(token, parser)
    nodelist = parser.parse(('end_tabbar',))
    return TabBarNode(nodelist)

Further, the TabBarNode class is taken for processing, which is initialized with a list of nodes (nodelist), which is rendered into the tabbar_content variable. The render method causes further parsing of all other nodes until all nodes are parsed and rendered to the state of a regular string, which can be inserted as a tabbar_content variable in the template and rendered using the render_to_string function in the render method. Have you noticed that
nodelist also has a render method?

class TabBarNode(template.Node):
    def __init__(self, nodelist):
        self.nodelist = nodelist

    def render(self, context):
        context.update({'tabbar_content': self.nodelist.render(context)})

        return render_to_string(


The template in this case looks rather trivial.

<div class="overflow-hidden">
  <div class="nav nav-tabs border-bottom flex-nowrap">
    {{ tabbar_content }}

tab_item tag in myapp.py file

But tab_item is already registered as inclusion_tag , and for understanding it is already simpler.

There are input arguments that are responsible for:

  • Text
  • Link
  • Indicate css link activity
@register.inclusion_tag('myapp/tab_item.html', takes_context=True)
def tab_item(context, title, url='#', active=False):
    return {
        'title': title,
        'url': url,
        'active': active,


And take a look at the tag template

<a class="text-nowrap nav-item nav-link{% if active %} active{% endif %}" href="{{ url }}">{{ title }}</a>


The result is a little simplified way to write a TabBar on a website using block tags.

We recommend hosting TIMEWEB
We recommend hosting TIMEWEB
Stable hosting, on which the social network EVILEG is located. For projects on Django we recommend VDS hosting.

Do you like it? Share on social networks!

  • March 24, 2023, 7:15 p.m.

Хорошая статья. И тут я подумал что на её основе можно отлично сформировать "хлебные крошки". Самое простое распарсить адрес. Так и поступил бы но лень

Evgenii Legotckoi
  • March 24, 2023, 8:09 p.m.

Почитайте эту статью про "хлебные крошки"

  • March 25, 2023, 12:35 a.m.

Да не я так к примеру просто написал.


Only authorized users can post comments.
Please, Log in or Sign up

C++ - Test 001. The first program and data types

  • Result:53points,
  • Rating points-4

C++ - Тест 003. Условия и циклы

  • Result:57points,
  • Rating points-2

C++ - Test 005. Structures and Classes

  • Result:100points,
  • Rating points10
Last comments
JonnyJoMay 25, 2023, 2:24 p.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Евгений, благодарю!
Evgenii Legotckoi
Evgenii LegotckoiMay 25, 2023, 4:49 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Код на строчка 184-198 вызывает перерисовку области на каждый 4-й такт счётчика. По той логике не нужно перерисовывать объект постоянно, достаточно реже, чем выполняется игровой слот. А слот вып…
JonnyJoMay 21, 2023, 10:49 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Евгений, благодарю! Всё равно не совсем понимаю :( Если муха двигает ножками только при нажатии клавиш перемещение, то что, собственно, делает код со строк 184-198 в triangle.cpp? В этих строчка…
Evgenii Legotckoi
Evgenii LegotckoiMay 21, 2023, 5:57 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Добрый день. slotGameTimer срабатывает по таймеру и при каждой сработке countForSteps увеличивается на 1, это не зависит от нажатия клавиш, нажатая клавиша лишь определяет положение ножек, котор…
JonnyJoMay 20, 2023, 11:27 a.m.
How to make game using Qt - Lesson 2. Animation game hero (2D) Евгений, здравствуйте! Подскажите, а почему при нажатии одной клавиши переменная countForSteps увеличивается не на 1, на 4, ведь одно действие даёт увеличение этой переменной только на единицу? …
Now discuss on the forum
Evgenii Legotckoi
Evgenii LegotckoiApril 16, 2023, 4:07 a.m.
Мобильное приложение на C++Qt и бэкенд к нему на Django Rest Framework Да, это возможно. Но подобные вещи лучше запускать через celery. То есть drf принимает команду, и после этого регистрирует задачу в celery, котроый уже асинхронно всё это выполняет. В противном …
Алексей БобровDec. 14, 2021, 7:03 p.m.
Sorting the added QML elements in the ListModel I am writing an alarm clock in QML, I am required to sort the alarms in ascending order (depending on the date or time (if there are several alarms on the same day). I've done the sorting …
Evgenii Legotckoi
Evgenii LegotckoiMarch 29, 2023, 4:11 a.m.
Замена поля ManyToMany Картинки точно нужно хранить в медиа директории на сервере, а для обращения использовать ImageField. Который будет хранить только путь к изображению на сервере. Хранить изображения в базе данных…
Evgenii Legotckoi
Evgenii LegotckoiApril 24, 2023, 3:22 a.m.
Пакеты данных между сервером и клиентами Привет. Если классы имеют что-то общее в полях, а также общую идеологию и их можно вписать в иерархию наследования, то в первую очередь переписать так, чтобы один базовый класс объединял в…

Follow us in social networks