Sunday, February 5, 2012

Розширення шаблонів Django

До початку створення філтру потрібно створити каталог templatetags  з файлом __init__.py який вкаже що це папка для пітона і відповідно файл з фільтрами який має мати говорящу назву, оскільки саме з допомогою назви файлу оприділяються наші фільтри в шаблоні, ось так:

{% load ext_filters %} # де ext_filters - це імя нашого файлу
{{ var|cut:"a" }} # це приклад використання фільтру

Власне і вміст нашого файлу:
from django import template
register = template.Library()

@register.filter(name='cut') # можна не вказувати назву філтра, тоді буде 
def cut(value, arg):            взята назва функції
    return  value.replace(arg, '')

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

- - - - - - -
Що стосується розширення тегів то тут малость складніше, але алгоритм той самий окрім того що потрібно створити екземпляр класа. Приклад простого тега:
from django import template

register = template.Library()

class MyTagNode(template.Node):

    def __init__(self, value, var_name):
        self.value = value
        self.var_name = var_name

    def render(self, context):
        context[self.var_name] = '__'+self.value+'__'
        return ''

@register.tag(name='wrapper')
def do_wrapper(parser, token):
    try:
        tag_name, value, var_name = token.contents.split()
    except ValueError:
        msg = '%r tag requires arguments' % token.contents[0]
        raise template.TemplateSyntaxError(msg)

    return MyTaskNode(value, var_name)

даний приклад нічого хорошого не робить, але явно показує застосування простого тегу який отримує на вхід два параметри(що видно з __init__) першим іде значення змінної а другим назва яку можна в подальшому використати в шаблоні:

{% wrapper item wname %}
{{wname}} # результат буде __item__

сам наш тег не вертає жодного результатату що видно з функції render, але зате показує як можна вставити знацення в контекст, а потім вже його використати.
Іншим прикладом може бути тег який обрамляє певні дані, при чому контент який міститься між крайніми тегами буде виконаний коректно завдяки self.nodelist.render(context) де поточний тег був видалений з допомогою  parser:

class ContainNode(template.Node):

    def __init__(self, nodelist):
        self.nodelist = nodelist

    def render(self, context):
        output = self.nodelist.render(context)
        return output.upper()
    
@register.tag(name='container')
def do_container(parser, token):
    nodelist = parser.parse(('endcontainer',))
    parser.delete_first_token()
    return ContainNode(nodelist)

в ноде ми передаємо вміст що знаходиться між тегами.
- - - - - - -
Також існує простіший варіант використання власного тегу, а саме тег який може отримувати тільки один параметер може бути визначений з допомогою simple_tag:

@register.simple_tag
def simpl(var):
    return var+'_SIMPL_' #робимо те що нам потрібно з отриманими даними

{% simpl var %} # для виклику з шаблону

при цьому не треба виконувати розширення від ноди, оскільки simpl_tag зробить це за нас.
- - - - - - -
Є ще один цікавий варіант, а саме тег з використанням іншого шаблону, виглядає це так:

@register.inclusion_tag('link.html', takes_context=True)
def name_tag(context, var)
     return {'var1':var, 'var2':context['var_name']}

все що тут потрібне це шаблон, і дані які повертає функція для шаблону, щоб мати можливість використовувати поточний контекст для формування даних що відселаються в шаблон потрібно використовувати другий параметер + першим параметром в функцію має іти context, далі використовуємо дані в шаблоні як душі завгодно. 
Звідси можна зробити підсумок що хоча два останні варіанти виглядають достатньо простими вони забезпечують хорошою функціональністю. Попередній варіант з використанням ноди не є складніши, хоча але зате надає більше можливостей.

No comments:

Post a Comment

 
 
Blogger Templates