Evgenii Legotckoi
21 березня 2023 р. 04:17

Django - Урок 062. Як написати блочний шаблонний тег tabbar на кшталт тега blocktranslate

У цій статті розповім про те, як саме можна написати простий блоковий шаблонний тег, на кшталт тега blocktranslate у Django .

Такі блокові шаблонні теги мають тег, що відкриває і закриває тег, і найбільш часто зустрічається я б назвав тег blocktranslate , який дозволяє перекладати цілий шматки коду html, а не тільки окремі пропозиції. Виглядати такий тег буде наступним чином.

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

У даному випадку тег має тег, що відкриває blocktranslate і закриває тег endblocktranslate , а з контентом усередині відбувається певна маніпуляція.

Особисто я написав кілька простих тегів для спрощення написання коду шаблонів на сайті. Одним з таких тегів є тег tabber усередині якого я також використовую теги tab_item .

Це скорочує написання коду в шаблонах і робить шаблон більш доброзичливим і більш легко піддається підтримці.

У результаті код шаблону у мене може мати такий вигляд.

{% 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 %}

В результаті дані шаблонні теги генерують наступний HTML код

<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>
  </div>
</div>

Як бачите, тут генерується досить стандартний для bootstrap код Tab Bar.

І якщо цей конкретний випадок можливо не є чимось, що може вимагати написання такого тега, то знання, як написати подібний тег може стати в нагоді в більш складних варіантах верстки, або там, де на сайті багато місць використання подібних табів. Що буде дуже корисно, оскільки для зміни верстки у всіх частинах сайту достатньо буде змінити лише код цих шаблонних тегів.

А тепер приступимо до вивчення, як написати такий шаблонний тег.

Структура програми

Допустимо у нас є додаток myapp , який міститиме дані шаблонні теги. Для цього необхідно, щоб у цьому додатку були створені директорії та файли з наступною структурою (крім тих, що створюються за замовчуванням)

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

тег tabbar у файлі myapp.py

Даний файл буде містити python код для обробки тега в шаблоні, а також поруч з ним знаходиться файл init .py, який ініціалізує myapp в директорії templatetags як бібліотека тегів. За замовчуванням файл порожній, але він там потрібен.

Для початку додамо необхідні імпорти

# -*- 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()

Після цього зареєструємо шаблонний тег. Важливий момент полягає в тому, що зазвичай функції, які реєструються як блоковий шаблонний тег, починаються з префікса do_ . Як бачите в коді нижче, як тільки парсер Django знаходить тег {% tabbar %}, то він відразу починає парсить шаблон у вигляді списку нод, тега, що закриває, який в даному випадку названий end_tabbar , при цьому перший токен з парсер видаляється. Як я зрозумів це видаляється нода, всередині якої був знайдений tabbar тег, в результаті він вже не обробляється. Список нод передається в кастомний клас ноди (TabBarNode) для подальшої обробки.

@register.tag("tabbar")
def do_tabbar(parser, token):
    tag_name, args, kwargs = parse_tag(token, parser)
    nodelist = parser.parse(('end_tabbar',))
    parser.delete_first_token()
    return TabBarNode(nodelist)

Далі за обробку приймається клас TabBarNode , який ініціалізується списком нод (nodelist), що рендерується у змінну tabbar_content . Метод render викликає подальший парсинг всіх інших нод, поки всі ноди не розпарсуються і не відрендеряться до стану звичайного рядка, який можна вставити у вигляді змінної tabbar_content шаблон і відрендерити за допомогою функції render_to_string у методі render . Ви помітили, що
nodelist також має метод render ?

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(
            template_name='myapp/tabbar.html',
            context=context.flatten()
        )

tabbar.html

Шаблон у разі виглядає досить тривіально.

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

тег tab_item в файле myapp.py

А ось tab_item реєструємо вже як inclusion_tag , і для розуміння він уже більш простий.

Тут є вхідні аргументи, які відповідають за:

  • Текст
  • Посилання
  • Вказівка css активності посилання
@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,
    }

tab_item.html

І поглянемо на шаблон тега

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

Висновок

В результаті вийшов невеликий спрощений спосіб написання TabBar на сайті за допомогою блокових тегів.

Вам це подобається? Поділіться в соціальних мережах!

NSProject
  • 24 березня 2023 р. 19:15

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

Evgenii Legotckoi
  • 24 березня 2023 р. 20:09

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

NSProject
  • 25 березня 2023 р. 00:35

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

Коментарі

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