пятница, 4 января 2013 г.

Django. Template tag с закрытием

Собственно, в джанге в родном шаблонизаторе есть возможность писать свои теги и фильтры.

А вот у меня встала задача. Есть какой-то контент, ну к примеру формируется он так:
 # some_template.html  ;

<div class="head-ev-bg">
    <div class="head-ev-numb">
        <div class="ev-character ev-{{ number }}"></div>
    </div>
    <div class="head-ev-l"></div><div class="head-ev-r"></div>
    <div><h4 class="titlec">{{ title }}</h4></div>
</div>
<div class="ev-cont">
    <div class="ev-cont-bg">
    {{ content }}
    </div>
    <div class="ev-cont-bt"></div>
</div>


Ну вроде бы ничего так. Надо передать какое-то число, заголовок и контент.
Беда в том, что контент - это ещё куча html кода. И вот выше изложенная последовательность повторяется пару раз на странице. Обычный тег должен проглотить контент через параметр.
К примеру:
{% some_tag "number" "title" "content" %}
Всё было бы не плохо, если бы не листинг в две страницы в этом поле "content" ))) Как-то сразу отпадает желание.
Вот и подумалось мне, ну раз есть {% for %} {% endfor %}, то наверное можно так же написать свой собственный тег, тег с закрытием.
А для меня он будет выглядеть так:
{% some_tag "number" "title" %}
content
{% endsome_tag %}

Красиво? Ну вот и я так считаю. Что же, а теперь листинг кода.

from django import template

register = template.Library()

class SomeTagNode(template.Node):
    def __init__(self, nodelist, id, title):
        self.nodelist = nodelist
        self.id = id
        self.title = title

    def render(self, context):
        output = self.nodelist.render(context) # выдаст то, что было между открывающим тегом и закрывающим
        t = template.loader.get_template('some_template.html')
        c = template.Context({ 'number': self.id, 'title': self.title, 'content': output})
        return t.render(c) # формируем шаблон и выводим

def do_sometag(parser, token):
# parser - структура шаблона
# token - то, что передадим тегу в качестве параметров
    try:
        tag_name, id, title = token.split_contents()
    except ValueError:
# Для меня важно получить два параметра
        raise template.TemplateSyntaxError("%r tag requires exactly two arguments" % token.contents.split()[0])
# Проверяю, что бы каждый параметр шёл в кавычках
    if not (id[0] == id[-1] and id[0] in ('"', "'")):
        raise template.TemplateSyntaxError("%r tag's first argument should be in quotes" % tag_name)

    if not (title[0] == title[-1] and title[0] in ('"', "'")):
        raise template.TemplateSyntaxError("%r tag's second argument should be in quotes" % tag_name)

    nodelist = parser.parse(('endsometag',)) # построить структуру до заданного тега
    parser.delete_first_token() 
    return SomeTagNode(nodelist, id[1:-1], title[1:-1]) # отправим струкуру

register.tag('sometag, do_sometag) # загрузим наше представление тега в общую библиотеку


P.S.: Я ничего не сделал того, что не описано в документаци к джанго. Даже более, это есть практически в таком виде в самой документации. Но, почитать и понять придется.
P.P.S.: Для меня это было в качестве упражнения и не более, т.к. html структура была вот такой, какой я её здесь описал. Но, с другой стороны, теперь мне, если  придется поменять структуру, то я буду делать это в одном шаблоне, а не в десяти местах в разных шаблонах, что радует.

Комментариев нет: