# documentação Django 2.0.8

# “Template tags” e filtros customizados

A linguagem de templates do Django vem com uma variedade de built-in tags e filtros projetados para atender as necessidades da lógica de apresentação da sua aplicação. Mesmo assim, talvez precise de uma funcionalidade que não está coberta pelo conjunto das primitivas do template. É possível estender o engine de templates definindo tags e filtros customizados usando Python, e então torná-los disponíveis para seus templates usando a tag `{% load %}` .

## Layout do código

O lugar mais comum para especificar tags e filtros customizados é dentro de uma app Django. Se eles estão relacionados a uma app existente, faz sentido empacotá-los ali; se não eles podem ser adicionados a uma nova app. Quando uma app Django é adicionada ao `INSTALLED_APPS`, qualquer tag que estiver definida em um local convencional descrito abaixo ficam automaticamente disponíveis para serem carregadas dentro dos templates.

A app deve conter um diretório `templatetags`, no mesmo nível que o `models.py`, ``views.py`, etc. Se este ainda não existe, crie - não esqueça o arquivo ``__init__.py` para ter certeza que o diretório é tratado como um pacote Python.

O servidor de desenvolvimento não irá reiniciar automaticamente

Depois de adicionar o módulo `templatags`, será preciso reiniciar o servidor antes que seja possível utilizar as tags ou filtros nos tempates.

As tags e filtros personalizados irão ficar em um módulo dentro do diretório ``templatetags`. O nome do arquivo do módulo é o nome que será usado para carregar as tags mais tarde, então tenha cuidado em escolher um nome que não conflite com tags e filtros customizados de outras apps.

Por exemplo, se suas tags/filtros customizados estão em um arquivo chamado ``poll_extras.py`, o layout da app deve parecer como isso:

    polls/
        __init__.py
        models.py
        templatetags/
            __init__.py
            poll_extras.py
        views.py

E no seu template você deveria usar o seguinte:

    {% load poll_extras %}

A app que contém a tag personalizada deve estar em `INSTALLED_APPS` para que a tag `{% load %}` funcione. Essa é uma característica de segurança: isso permite servir código Python para muitas bibliotecas de template em uma única máquina servidora sem habilitar acesso cada instalação de Django.

Não há limites de quantos módulos são colocados dentro do pacote `templatetags`. Apenas mantenha em mente que um comando `{% load %}` irá carregar tags/filters para o nome do módulo Python, e não o nome da app.

Para ser uma biblioteca de tags válida, o módulo deve conter uma variável do nível do módulo chamado `register` que é uma instância de `template.Library`, na qual todas as tags e filtros são registrados. Então, próximo ao topo do seu módulo, coloque o seguinte:

    from django import template

    register = template.Library()

Um alternativa, é que módulos de tags de template podem ser registradas através do argumento `'libraries'` do `DjangoTemplates`. Isso é útil se você quer um “label” diferente para o módulo da tag de quando carregar os templates. Isso também habilita o registro de tags sem instalar a aplicação.

Por trás das cenas.

Para uma tonelada de exemplos, leia o código fonte das tags e filtros padrão do Django. Eles estão em `django/template/defaultfilters.py` e `django/template/defaulttags.py`, respectivamente.

Para maiores informações sobre a tag `load` tag, leia sua documentação

## Escrevendo filtros de templates personalizados

Filtros customizados são apenas funções Python que recebem um ou dois argumentos:

- O valor da variável (input - de entrada) – não necessariamente uma string.
- O valor do argumento – este pode ter um valor padrão, ou ser deixado de fora.

Por exemplo, no filtro `{{ var|foo:"bar" }}`, ao filtro `foo` seria passada a variável `var` e o argumento `"bar"`.

Uma vez que a linguagem de template não fornece manipulação de exceções, qualquer exceção vinda de um filtro de template será exposta como um erro de servidor. Sendo assim, funções de filtros devem evitar enviar exceções se houver um valor substituto razoável para retornar. No caso de uma entrada que representa claramente um bug em um template, enviar uma exceção talvez ainda seja melhor que uma falha silenciosa a qual esconde o bug.

Aqui um exemplo de definição de filtro:

    def cut(value, arg):
        """Removes all values of arg from the given string"""
        return value.replace(arg, '')

E aqui um exemplo de como aquele filtro poderia ser usado:

    {{ somevariable|cut:"0" }}

A maioria dos filtros não recebe argumentos. Neste caso, somente deixe o argumento de sua função vazio. Exemplo:

    def lower(value): # Only one argument.
        """Converts a string into all lowercase"""
        return value.lower()

### Registrando filtros customizados

`django.template.Library.``filter`()

Uma vez que tenha escrito sua definição do filtro, é preciso registrá-lo com sua instância de `Library`, para fazer com que esteja disponível para a linguagem de template do Django.

    register.filter('cut', cut)
    register.filter('lower', lower)

O Método `Library.filter()` recebe dois argumentos:

1. O nome do filtro – uma string.
2. A função de compilação – uma função Python (não o nome da função como uma string)

Você pode, ao invés, usar `register.filter()` como um decorador:

    @register.filter(name='cut')
    def cut(value, arg):
        return value.replace(arg, '')

    @register.filter
    def lower(value):
        return value.lower()

Se deixar de passar o argumento `name`, como no segundo exemplo acima, o Django irá usar o nome da função como nome do filtro.

Finalmente, `register.filter()` também aceita três argumentos nomeados, `is_safe`, `needs_autoescape`, e `expects_localtime`. Estes argumentos são descrito em filters and auto-escaping e filters and time zones abaixo.

### Filtros de templates que recebem strings

`django.template.defaultfilters.``stringfilter`()

Se você está escrevendo um filtro de template que somente aceita uma string como primeiro argumento, deveria usar o decorador `stringfilter`. Isso irá converter um objeto para seu valor string antes de ser passado pela sua função:

    from django import template
    from django.template.defaultfilters import stringfilter

    register = template.Library()

    @register.filter
    @stringfilter
    def lower(value):
        return value.lower()

Desta maneira, você será capaz de passar, vamos dizer, um inteiro para este filtro, e isso não irá causar um `AttributeError` (porque inteiros não possuem os métodos `lower()`).

### Filtros e auto-escaping

When writing a custom filter, give some thought to how the filter will interact with Django’s auto-escaping behavior. Note that two types of strings can be passed around inside the template code:

- Raw strings are the native Python strings. On output, they’re escaped if auto-escaping is in effect and presented unchanged, otherwise.

- Safe strings são strings que tenham sido marcadas como seguras para futuros “escaping” no tempo de saída. Qualquer “escaping” necessário já foi feito. Eles são comumente usados para saídas que contenham HTML puro que se destina a ser interpretado como estão do lado do cliente.

  Internally, these strings are of type `SafeText`. You can test for them using code like:

      from django.utils.safestring import SafeText

      if isinstance(value, SafeText):
          # Do something with the "safe" string.
          ...

Código de filtros de templates caem em um das duas situações:

1. Seu filtro não introduz qualquer caracter HTML inseguro (`<`, `>`, `'`, `"` or `&`) no resultado que ainda não foi apresentado. Neste caso, você pode deixar o Django cuidar de toda a manipulação do “auto-espacaping” pra você. Tudo o que precisa é definir a “flag” ìs_safe``para ``True` quando registrar a função do filtro, como:

       @register.filter(is_safe=True)
       def myfilter(value):
           return value

   A “flag” diz ao Django que se uma string “segura” é passada para seu filtro, o resultado ainda será “seguro” e se uma string não segura é passada, Django irá automaticamente fazer o “escape”, se necessário.

   Você pode entender isso como “este filtro é seguro – ele não introduz qualquer possibilidade de HTML não seguro”

   The reason `is_safe` is necessary is because there are plenty of normal string operations that will turn a `SafeData` object back into a normal `str` object and, rather than try to catch them all, which would be very difficult, Django repairs the damage after the filter has completed.

   Por exemplo, suponha que tenha um filtro que adiciona a string `xx``ao final de uma entrada. Uma vez que isso não introduz nenhum caracter HTML perigoso para o resultado (além daqueles que já estão presentes), você deveria marcar seu filtro como ``is_safe`:

       @register.filter(is_safe=True)
       def add_xx(value):
           return '%sxx' % value

   Quando o filtro é usado em um template onde a auto-substituição está habilitada, o Django irá fazer a substituição na saída sempre que a entrada ainda não estiver marcada como “safe”.

   Por padrão, `is_safe` é `falso`, e você pode omiti-lo em qualquer filtro onde ele não é requerido.

   Tenha cuidado quando estiver decidindo se o seu filtro realmente irá deixar strings seguras como “safe”. Se estiver “removendo” caracteres, poderia deixar tags HTML ou entidades incompletas no resultado. Por exemplo, removendo um `>``de uma entrada poderia tornar ``<a>` em um `<a`, que poderia ser necessário fazer o “escape” na saída para evitar causar problemas. Similar a isso, removendo um ponto-e-vírgula (`;`) pode tornar um `& amp;` em um `& amp` , o qual não é mais uma entidade válida e assim precisa realizar o “escape”. A maioria dos casos nem chegarão perto de ser complicados assim, mas fique de olho para qualquer problema como este quando revisar seu código.

   Fazendo um filtro `is_safe` obriga que este retorne um valor do tipo string. Se o seu filtro deveria retornar uma boolean ou outro valor que não uma string, marcar isso como `is_safe` provavelmente terá consequências inexperadas (tal como converter um booleano “False” para a string ‘False’).

2. Uma alternativa, o código do seu filtro pode manualmente cuidar das substituições necessárias. Isso é necessário quando adicionar uma marcação HTML ao resultado. Você quer marcar a saída como segura de substituições posteriores, então suas marcação HTML não será substituída, e precisará tratar a entrada por conta própria.

   Para marcar a saída como saída segura, use `django.utils.safestring.mark_safe()`.

   Porém, tenha cuidado. É necessário mais que marcar a saída como segura. É necessário ter certeza que isso é realmente seguro, e o que fará depende se a auto-substituição está fazendo efeito. A idéia é escrever filtros que podem operar em templates onde o auto-escaping está ligado ou desligado de modo a tornar as coisas mais fáceis para os autores de templates.

   Para que seu filtro saiba o estado corrente do estado da auto-substituição, defina a flag `needs_autoescape` como `True` quando registrar o filtro. (se não especificar esa flag, seu valor padrão é `False`). Esta flag dia ao Django que sua função do filtro quer que seja passado um argumento extra, chamado `autoescape`, que é ``True` se está em efeito e `False``caso contrário. É recomendado definir o padrão do parâmetro ``autoescape` para `True`, então se a função for chamado de um código Python esta terá a substituição habilitada por padrão.

   Por exemplo, vamos escrever um filtro que enfatiza o primeiro caracter de uma string:

       from django import template
       from django.utils.html import conditional_escape
       from django.utils.safestring import mark_safe

       register = template.Library()

       @register.filter(needs_autoescape=True)
       def initial_letter_filter(text, autoescape=True):
           first, other = text[0], text[1:]
           if autoescape:
               esc = conditional_escape
           else:
               esc = lambda x: x
           result = '<strong>%s</strong>%s' % (esc(first), esc(other))
           return mark_safe(result)

   A flag `needs_autoescape` e o argumento nomeado `autoescape` implicam que nossa função irá sabe se a substituição automática está efetiva quando o filtro for chamado. Usamos o `autoescape` para decidir se o data de entrada precisa ser acessado através do `django.utils.html.conditional_escape` ou não. (No último caso, usamos a função identidade como função de “substituição”). A função `conditional_escape()` é como `escape()` exceto que somente substitui a entrada que não é instância de `SafeData`. Se uma instância de `SafeData` é passada para a `conditional_escape()`, o dado é retornado sem mudanças.

   Finalmente, no exemplo acima, relembramos de marcar resultados como seguros assim que o HTML é inserido diretamente no template sem outras substituições.

   Não precisa se preocupar com a flag `is_safe` neste caso (embora inclui-la não faria nenhum mal). Mesmo que trate manualmente a auto-substituição e retorne uma string segura, a flag `is_safe` não alterará nada de nenhum modo.

Aviso

Evitando vulnerabilidade XSS quando reusar filtros embutidos.

Os fiiltros embutidos do Django tem por padrão `autoescape=True` para que receba propriamente o comportamento da auto-substituição e evite a vulnerabilidade de “cross-site” .

Em versões antigas do Djagno, tenha cuidado quando reutilizar filtros embutidos como `autoescape` definidos por padrão como `None`. Será necessário passar `autoescape=True` para ter a auto-substituição.

Por exemplo, se quer escrever um filtro personalizado chamado ``urlize_and_linebreaks``que combine os filtros `urlize` e `linebreaksbr`, o filtro deveria parecer com:

    from django.template.defaultfilters import linebreaksbr, urlize

    @register.filter(needs_autoescape=True)
    def urlize_and_linebreaks(text, autoescape=True):
        return linebreaksbr(
            urlize(text, autoescape=autoescape),
            autoescape=autoescape
        )

Então:

    {{ comment|urlize_and_linebreaks }}

seria equivalente a:

    {{ comment|urlize|linebreaksbr }}

### Filtros e fusos horários

Se escrever filtros personalizados que operam objetos `datetime`, geralmente registra-se com a flag `expects_localtime``definido como ``True`:

    @register.filter(expects_localtime=True)
    def businesshours(value):
        try:
            return 9 <= value.hour < 17
        except AttributeError:
            return ''

Quando esta flag está definida, se o primeiro argumento do seu filtro é uma date-time que leva em consideração o fuso-horário, o Django irá convertê-lo para o fuso-horário corrente antes de passa-lo para o filtro quando apropriado, de acordo com rules for time zones conversions in templates.

## Escrevendo tags de templates personalizadas.

Tags são mais complexas que filtros, porque as tags podem fazer qualquer coisa. Django fornece inúmeros atalhos para fazer com que a escrita de várias tags seja mais fácil. Primeiro iremos explorar estes atalhos, e então explicar como escrever uma tag do início para aqueles casos em que os atalhos não são poderosos o suficiente.

### Tags simples

`django.template.Library.``simple_tag`()

Muitas tags de templates recebem inúmeros argumentos – strings ou variáveis de templates – e retornam um resultado depois de fazer algum processamento baseado somente nos argumentos de entrada e alguma informação externa. Por exemplo, uma tag `current_time` aceitaria uma string de formato e retorna a hora como uma string formatada de acordo.

Para facilitar a criação destes tipos de tags, Django fornece uma função de auxílio, `simple_tag`. Essa função, a qual é um método de `django.template.Library`, tem uma função que recebe qualquer número de parâmetros, empacota isso em uma função `renderizadora` junto com os “bits” mencionados acima e o registra com o sistema de templates.

Nossa função `current_time` poderia então ser escrita assim:

    import datetime
    from django import template

    register = template.Library()

    @register.simple_tag
    def current_time(format_string):
        return datetime.datetime.now().strftime(format_string)

Algumas coisas para perceber sobre a função de auxílio `simple_tag`:

- A checagem do número de arrgumentos, etc, já foi feito na hora em que a função é chamada, então não precisamos faze-lo.
- As aspas ao redor do argumento (se existem) já foram retiradas, então recebemos uma string simples.
- Se o argumento era uma variável de template, é passada par a nossa função o valor atual da variável, e não a própria variável.

Diferente de outras ferramentas de tag, `simple_tag` passa sua saida através do `conditional_escape()` se o contexto do tempte está no modo auto-substituição, para assegurar o HTML e proteger da vulnerabilidade XSS.

Se substituições adicionais não são desejadas, é necessário usar `mark_safe()` se você tem a certeza absoluta que seu código não contém vulnerabilidade XSS. Para construir pequenos fragmentos de HTML, é fortemente recomendado usar `format_html()` ao invés de `mark_safe()`

Se a template tag precisa acessar o contexto corrente, você pode usar o argumento `takes_context` quando registrá-la:

    @register.simple_tag(takes_context=True)
    def current_time(context, format_string):
        timezone = context['timezone']
        return your_get_current_time_method(timezone, format_string)

Perceba que o primeiro argumento deve ser chamado “context”.

Para maiores informações sobre como a opção `takes_context` funciona, veja a seção inclusion tags.

Se você precisar renomear a tag, você pode fornecer um nome personalizado para ele:

    register.simple_tag(lambda x: x - 1, name='minusone')

    @register.simple_tag(name='minustwo')
    def some_function(value):
        return value - 2

As funções `simple_tag` aceitam qualquer número de argumentos posicionais ou nomeados. Por exemplo:

    @register.simple_tag
    def my_tag(a, b, *args, **kwargs):
        warning = kwargs['warning']
        profile = kwargs['profile']
        ...
        return ...

Então no template qualquer número de argumentos, separados por espaços podem ser passados para a atg de template. Como em Python, os valores para argumentos nomeados são definidos usando o sinal de igua (“=”) e devem ser fornecidos depois dos argumentos posicionais. Por exemplo:

    {% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}

É possível armazenar os resultados da tag em uma variável de template ao invés de enviar para a saída diretamente. Isso é feito utilizando o argumento `as` seguido de um nome de variável. Fazendo isso é possível posicionar o conteúdo onde você achar cabido.

    {% current_time "%Y-%m-%d %I:%M %p" as the_time %}
    <p>The time is {{ the_time }}.</p>

### Tags de inclusão

`django.template.Library.``inclusion_tag`()

Outro tipo de tag de template é o tipo que mostra alguns dados renderizados por outro template. Por exemplo, a interface do Admin do Django usa tags de tempate para mostrar os botões ao longo do final das páginas de formulários “add/change”. Esses botões sempre parecem os mesmos, mas o link de destino mudam dependendo do objeto sendo editado – então são um perfeito caso para usar um template pequeno que é preenchido com detalhes do objeto atual. (No caso do Admin, essa é a tag `submit_row`.)

Este tipo de Tag são chamadas “tags de inclusão”

Escrever tags de inclusão é provavelmente melhor demonstrado através de exemplos. Vamos escrever uma Tag que devolve uma lista de opções para um dado objeto `Poll`, tal como o que foi criado no tutorials. Usaremos a tag assim:

    {% show_results poll %}

…e a saída será algo como:

    <ul>
      <li>First choice</li>
      <li>Second choice</li>
      <li>Third choice</li>
    </ul>

Primeiro defina a função que recebe os argumentos e produz um dicionário de dados para o resultado. O ponto importante aqui é que precisamos somente retornar um dicionário, não algo mais complexo. Isso será usado como um contexto para o fragmento de template. Exemplo:

    def show_results(poll):
        choices = poll.choice_set.all()
        return {'choices': choices}

Depois, criamos o template que irá renderizar a saída da tag. Este template é uma característica fixa da tag: o autor da tag especifica isso, não o designer de template. Seguindo o exemplo, o template é muito simples.

    <ul>
    {% for choice in choices %}
        <li> {{ choice }} </li>
    {% endfor %}
    </ul>

Agora, crie e registre a tag de inclusão chamando o método `inclusion_tag()` em um objeto do tipo `Library`. Seguindo nosso exemplo, se o exemplo acima é um arquivo chamado `results.html` em um diretório que é procurado pelo template loader, nós regitramos a tag assim:

    # Here, register is a django.template.Library instance, as before
    @register.inclusion_tag('results.html')
    def show_results(poll):
        ...

Alternativamente é possível registrar a tag de inclusão usando uma instância de `django.template.Template`:

    from django.template.loader import get_template
    t = get_template('results.html')
    register.inclusion_tag(t)(show_results)

…quando criar a função pela primeira vez.

Algumas vezes, sua tag de inclusão requer um número grande de argumentos, tornando uma dor de cabeça para autores dos templates passar todos os argumentos e lembrar sua ordem. Para resolver isso, o Django fornece uma opção `takes_context` para tags de inclusão. Se o especificado o `takes_context` na criação da tag de template, a tag não terá argumentos requeridos, e a função Python implícita terá um argumento – o contexto do template quando a tag foi chamada.

Por exemplo, digamos que esteja escrevendo uma tag de inclusão que sempre será usada em um contexto que contém as variásveis `home_link` e `home_title` que apontam de volta para a página principal. Aqui como a função Python deveria parecer:

    @register.inclusion_tag('link.html', takes_context=True)
    def jump_link(context):
        return {
            'link': context['home_link'],
            'title': context['home_title'],
        }

Repare que o primeiro parâmetro para a função deve ser chamado de `context`.

Na linha `register.inclusion_tag()`, especificamos o `takes_context=True` e o nome do template. Aqui o que o template `link.html` deve se parecer:

    Jump directly to <a href="{{ link }}">{{ title }}</a>.

Então, qualquer momento que queira usar a tag personalizada, carregue sua biblioteca e chame-a sem nenhum argumento, como:

    {% jump_link %}

Repare que quando estiver usando `takes_context=True`, não tem necessidade de passar argumentos para a tag de template. Esta tem acessa o contexto automaticamente.

O parâmetro padrão para `takes_context` é `False`. Quando definido como `True`, para tag é passado o objeto contexto, como neste exemplo. Este é a única diferença entre este caso e o exemplo `inclusion_tag` anterior.

Funções `inclusion_tag` podem aceitar qualquer número de argumentos posicionais ou nomeados. Por exemplo:

    @register.inclusion_tag('my_template.html')
    def my_tag(a, b, *args, **kwargs):
        warning = kwargs['warning']
        profile = kwargs['profile']
        ...
        return ...

Então no template qualquer número de argumentos, separados por espaços podem ser passados para a atg de template. Como em Python, os valores para argumentos nomeados são definidos usando o sinal de igua (“=”) e devem ser fornecidos depois dos argumentos posicionais. Por exemplo:

    {% my_tag 123 "abcd" book.title warning=message|lower profile=user.profile %}

### Tags personalizadas avançadas

As vezes as funções básicas para criação das tags de template não são o suficiente. Não se preocupe, o Django lhe dá completo acesso as “coisas”internas requeridas para construir uma tag de template do zero.

### Um rápida visão geral

O sistema de templates funciona em um processo de 2 passos.: compilação e renderização. Para definir uma tag de template personalizada, é necessário especificar como a compilação funcionar e como a renderização funciona.

Quando Django compila um template, o texto do template original é dividido em “nós”. Cada nó é uma instância de `django.template.Node` e tem um método `render()`. Um template compilado é, simplesmente, uma lista de objetos `Node`. Quando chama `render()` em um objeto template compilado, o template chama `render()``para cada ``Node` na sua lista de nós, com o dado contexto. Os resultados são todos concatenados juntos para formar a saída do template.

Então, para definir uma tag de template personalizada, especifique como a tag de template original é convertida em um `Nó` (a função de compilação), e o que o método ``render()``do nó faz.

### Escrevendo a função de compilação

Para cada tag de template que o analisador de templates encontra, ele chama uma função Python com o conteúdo da tag e o próprio objeto analisador. Essa função é responsável por retornar uma instância de `Node` baseada no conteúdo da tag.

Por exemplo, vamos escrever toda a implementação de uma simples tag de template, `{% current_time %}`, que mostra a data/hora corrente., formatada de acordo com um parâmetro passado na tag, na syntax `strftime()`. É uma boa idéia decidir a syntax antes de qualquer outro. No nosso caso, vamos dizer que a tag deveria ser assim:

    <p>The time is {% current_time "%Y-%m-%d %I:%M %p" %}.</p>

O analisador para essa função deve pegar o parâmetro e criar um objeto `Node`:

    from django import template

    def do_current_time(parser, token):
        try:
            # split_contents() knows not to split quoted strings.
            tag_name, format_string = token.split_contents()
        except ValueError:
            raise template.TemplateSyntaxError(
                "%r tag requires a single argument" % token.contents.split()[0]
            )
        if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
            raise template.TemplateSyntaxError(
                "%r tag's argument should be in quotes" % tag_name
            )
        return CurrentTimeNode(format_string[1:-1])

Notas:

- `parser` é o objeto analisador do template. Nós não precisamos dele neste exemplo.
- `token.contents` é uma string com o conteúdo original da tag, No nosso exemplo, isso é `'current_time "%Y-%m-%d %I:%M %p"'`.
- O método `token.split_contents()` separa os argumentos por espaços enquanto mantém strings entre aspas, juntas. Mais direto o `token.contents.split()` não seria tão robusto já que ingenuamente dividiria todos os espaços, incluindo aqueles dentro de aspas. É uma boa idéia usar sempre o `token.split_contents()`.
- Essa função é responsável for informar o `django.template.TemplateSyntaxError`, com mensagens de ajuda, para qualquer erro de sintaxe.
- As exceções `TemplateSyntaxError` usam a variável `tag_name`. Não coloque nomes de tags dentro de suas mensagens de erro, porque isso amarra o nome da tag a sua função. `token.contents.split()[0]` ‘’sempre’’ será o nome da sua tag – mesmo quando sua tag não tem argumentos.
- A função retorna um `CurrentTimeNode` com tudo que o nó precisa para conhecer sobre sua tag. Neste caso, ele apenas passa o argumento – `"%Y-%m-%d %I:%M %p"`. As aspas (direita e esquerda) da tag de template estão removidas em `format_string[1:-1]`.
- O analisador é muito baixo nível. Os desenvolvedores do Django experimentaram escrever pequenos frameworks baseados no sistema analisador (“parser”), usando técnicas como a gramática EBNF, mas estes experimentos tornaram o motor de template muito lento. É baixo-nível porque é rápido.

### Escrevendo o “renderizador”

O segundo passo para escrever uma tag personalizada é definir uma subclasse de `Node` que tenha um método `render()`.

Continuando o exemplo acima, precisamso definir `CurrentTimeNode`:

    import datetime
    from django import template

    class CurrentTimeNode(template.Node):
        def __init__(self, format_string):
            self.format_string = format_string

        def render(self, context):
            return datetime.datetime.now().strftime(self.format_string)

Notas:

- `__init__()` recebe o `format_string` do `do_current_time()`. Sempre passar opções/parametros/argumentos para um `Node` através de seu `__init__()`.
- O método `render()` é onde o trabalho realmente acontece
- `render()` deve geralmente falhar silenciosamente, particularmente no ambiente de produção. Em alguns casos porém, particularmente se `context.template.engine.debug` for `True`, este método pode indicar uma exceção para ficar mais fácil debugar. Por exemplo, muitas tags do core inviam `django.template.TemplateSyntaxError` se eles receberem o número errado ou tipo de argumentos.

Por último, este desacomplamento entre compilação e renderização resulta em um sistema de template mais eficiente, porque o template pode renderizar múltiplos contextos ser ter que ser analisado (“parsed”) múltiplas vezes.

### Considerações sobre auto-substituição

A saída da tag de template não passa automaticamente pelos filtros de auto-escaping (com exceção do `simple_tag()` , como descrito acima). Porém, ainda existem algumas coisas para se ter em mente ao escrever uma tag de template.

Se a função `render()` do seu template armazena o resultado em uma variável de contexto (ao invés de retornar o resultado em uma string), ele deve tomar o cuidado de chamar ``mark_safe()``se apropriado. Quando a variável é renderizada, ela será afetada pela definição do auto-substituição em efeito na hora, então o conteúdo que deve ser ignorado em futuras substituições deve ser marcado como tal.

Também, se sua tag cria um novo contexto para realizar algum sub renderização, defina o atributo de auto-substituição para o valor do contexto corrente. O método `__init__` da classe `Context` recebe um parâmetro chamado `autoescape` que pode ser usado para este propósito. Por exemplo:

    from django.template import Context

    def render(self, context):
        # ...
        new_context = Context({'var': obj}, autoescape=context.autoescape)
        # ... Do something with new_context ...

Isso não é uma situação muito comum, mas é útil se você está renderizando você mesmo o template. Por exemplo:

    def render(self, context):
        t = context.template.engine.get_template('small_fragment.html')
        return t.render(Context({'var': obj}, autoescape=context.autoescape))

Se negligenciássemos ao passar o valor no corrente `context.autoescape` para ao novo `Context` neste exemplo, os resultados seriam sempre automaticamente substituidos, o que pode não ser o comportamento desejável se a tg de template for usada dentro de um bloco `{% autoescape off %}` .

### Considerações sobre segurança de “thread”

Uma vez que o nó tenha sido analisado, seu método `render` pode ser chamado qualquer número de vezes. Uma vez que o Django roda algumas vezes em ambientes multi-threaded, um nó pode ser renderizado simultaneamente com diferentes contextos em resposta a dois requests diferentes. Por isso, é importante que suas tags de templates são segurara para “threads”.

Para ter certeza que sua tag de template é segura para rodar em threads, nunca deve armazenar informação no próprio nó. Por exemplo, Django fornece a template tag `cycle` que alterna os intens de uma lista de strings cada vez que é renderizada:

    {% for o in some_list %}
        <tr class="{% cycle 'row1' 'row2' %}">
            ...
        </tr>
    {% endfor %}

Uma implementação ingênua do `CycleNode` talvez se pareça como algo assim:

    import itertools
    from django import template

    class CycleNode(template.Node):
        def __init__(self, cyclevars):
            self.cycle_iter = itertools.cycle(cyclevars)

        def render(self, context):
            return next(self.cycle_iter)

Mas, suponha que temos dois templates renderizando o pedaço de template acima ao mesmo tempo.

1. Thread 1 realiza sua primeira iteração, `CycleNode.render()` retorna ‘row1’
2. Thread 2 realiza sua primeira iteração, `CycleNode.render()` retorna ‘row2’
3. Thread 1 realiza sua segunda iteração, `CycleNode.render()` retorna ‘row2’
4. Thread 2 realiza sua segunda iteração, `CycleNode.render()` retorna ‘row2’

O CycleNode está iterando, más iterando globalmente. Tanto quanto Thread 1 e Thread 2 são problemas, eles retornam sempre o mesmo valor. Isso não é obviamente o que queremos !

Para resolver o problema, o Django provê o `render_context` que associado com o `context` do template que está correntemente sendo renderizado. O `render_context` se comporta como um dicionário Python, e deve ser usado para armazenar os estados do `Node` entre chamadas do método `render`.

Vamos refatorar nosso implementação do `CycleNode` para usar o `render_context`:

    class CycleNode(template.Node):
        def __init__(self, cyclevars):
            self.cyclevars = cyclevars

        def render(self, context):
            if self not in context.render_context:
                context.render_context[self] = itertools.cycle(self.cyclevars)
            cycle_iter = context.render_context[self]
            return next(cycle_iter)

Note que é perfeitamente seguro armazenar informação global que não irá se alterar através da vida do `Node` como um atributo. No caso do `CycleNode`, o argumento `cyclevars` não muda depois que `Node` é instanciado., então não precisamos colocá-lo no `render_context`. Mas informações do estado que é específica para o template que está sendo renderizado no momento, como a citeração corrente do `CycleNode`, deve ser armazenado no `render_context`

Nota

Note como usamos o `self` como escopo para a informação específica do `CycleNode` dentro do `render_context`. Pode haver múltiplos `CycleNodes` em um dado template, então é preciso ter cuidado para não conflitar outra informação de estado do nó. A maneira mais fácil de fazer isso é sempre usar `self` como chave dentro do `render_context`. Se está acompanhando várias variáveis de estado faça do `render_context[self]` um dicionário.

### Registrando a tag

Finalmente, registre a tag com sua instancia de `Library` do modelo, como explicado em writing custom template filters acima. Exemplo:

    register.tag('current_time', do_current_time)

O método `tag()` recebe dois argumentos:

1. O nome da template tag – uma string. Se não for informado, o nome da função de compilação será usado.
2. A função de compilação – uma função Python (não o nome da função como uma string)

Assim como o registro de um filtro, também é possível usá-lo como “decorator”:

    @register.tag(name="current_time")
    def do_current_time(parser, token):
        ...

    @register.tag
    def shout(parser, token):
        ...

Se não informado o argumento `name`, como no segundo exemplo acima, o Django irá usar o nome da função como nome da tag.

### Passando variáveis de template para a tag.

Embora você possa passar qualquer número de argumentos para uma tag de template usando `token.split_contents()`, os argumentos são todos “desempacotados” como strings literais. Um pouco mais de trabalho é requerido para que passe o conteúdo dinamicamente (uma variável de template) para uma tag de template como argumento.

Enquando os exemplos anteriores formataram a hora corrente como string e retornaram uma string, suponha que queira passar um `DateTimeField` de um objeto e a template tag formate o date-time:

    <p>This post was last updated at {% format_time blog_entry.date_updated "%Y-%m-%d %I:%M %p" %}.</p>

Inicialmente, `token.split_contents()` irá retornar três valores:

1. A tag chamada `format_time`.
2. A string `'blog_entry.date_updated'` (sem as aspas).
3. A string de formatação `'"%Y-%m-%d %I:%M %p"'`. O valor retornado do `split_contents()` irá incluir as aspas para string literais como esta.

Agora sua tag deve começar a parecer com isso:

    from django import template

    def do_format_time(parser, token):
        try:
            # split_contents() knows not to split quoted strings.
            tag_name, date_to_be_formatted, format_string = token.split_contents()
        except ValueError:
            raise template.TemplateSyntaxError(
                "%r tag requires exactly two arguments" % token.contents.split()[0]
            )
        if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
            raise template.TemplateSyntaxError(
                "%r tag's argument should be in quotes" % tag_name
            )
        return FormatTimeNode(date_to_be_formatted, format_string[1:-1])

Também é necessário alterar o renderizador para retornar o conteúdo atual da propriedade `date_update` do objeto `blog_entry`.

Para usar a class `Variable`, simplesmente instancie-a com o nome da variável a ser resolvida, e então `variable.resolve(context)`. Então por exemplo:

    class FormatTimeNode(template.Node):
        def __init__(self, date_to_be_formatted, format_string):
            self.date_to_be_formatted = template.Variable(date_to_be_formatted)
            self.format_string = format_string

        def render(self, context):
            try:
                actual_date = self.date_to_be_formatted.resolve(context)
                return actual_date.strftime(self.format_string)
            except template.VariableDoesNotExist:
                return ''

A resolução da variável irá lançar uma excessão `VariableDoesNotExist` se não conseguir resolver a string recebida no contexto corrente da página.

### Definindo uma variável no contexto

Os exemplos acima simplesmente retornam um valor. Geralmente, é mais flexível se suas tags de template definem variáveis ao invés de retornar valores. Desde modo, autores de templates podem reutilizar valores que suas tags de templates criam.

Para definir uma variável no contexto, apenas use no objeto de contexto uma passagem de parâmetros por dicionário no método `render()`. Aqui uma versão atualizada de `CurrentTimeNode` que definie uma variável de template `current_time` ao invés de retornar uma saída:

    import datetime
    from django import template

    class CurrentTimeNode2(template.Node):
        def __init__(self, format_string):
            self.format_string = format_string
        def render(self, context):
            context['current_time'] = datetime.datetime.now().strftime(self.format_string)
            return ''

Repare que `render()` retorna uma string vazia. `render()` deve sempre retornar uma string como saída. Se tudo que a tag de template faz é definir uma variável, `render()` deve retornar uma string vazia.

Aqui como você deveria usar esta nova versão da tag:

    {% current_time "%Y-%M-%d %I:%M %p" %}<p>The time is {{ current_time }}.</p>

Escopo da variável no context

Qualquer variável definida no contexto somente estará disponível no mesmo “bloco” do template no qual ele foi definido. Este comportamento é intencional; ele fornece um escopo para as variáveis que então não conflitam com o contexto de outros blocos.

Mas, tem um problema com `CurrentTimeNode2`: O nome da variável `current_time` está “hardecodeada”. Isso significa que tem que ter certeza seu template não usa `{{ current_time }}` em nenhum outro lugar, porque o `{% current_time %}` irá redefinir o valor da variável. Uma solução mais limpa é fazer a tag de template especificar o nome da variável de saída, como:

    {% current_time "%Y-%M-%d %I:%M %p" as my_current_time %}
    <p>The current time is {{ my_current_time }}.</p>

Para fazer isso, será preciso refatorar a função de compilação e a classe de ``Node`, deste modo:

    import re

    class CurrentTimeNode3(template.Node):
        def __init__(self, format_string, var_name):
            self.format_string = format_string
            self.var_name = var_name
        def render(self, context):
            context[self.var_name] = datetime.datetime.now().strftime(self.format_string)
            return ''

    def do_current_time(parser, token):
        # This version uses a regular expression to parse tag contents.
        try:
            # Splitting by None == splitting by spaces.
            tag_name, arg = token.contents.split(None, 1)
        except ValueError:
            raise template.TemplateSyntaxError(
                "%r tag requires arguments" % token.contents.split()[0]
            )
        m = re.search(r'(.*?) as (\w+)', arg)
        if not m:
            raise template.TemplateSyntaxError("%r tag had invalid arguments" % tag_name)
        format_string, var_name = m.groups()
        if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):
            raise template.TemplateSyntaxError(
                "%r tag's argument should be in quotes" % tag_name
            )
        return CurrentTimeNode3(format_string[1:-1], var_name)

A diferença aqui é que `do_current_time()` pega a string de formato e o nome da variável passando ambos para `CurrenteNode3`.

Finalmente, se você precisa ter somente uma sinatxe simples para sua tag de template personalizada que atualiza o contexto, considere usar o atalho `simple_tag()`, o qual possibilita passar os resultados de uma tag para uma variável de template.

### “Parsing” até outra bloco de tag.

Tags de templates podem trabalhar em tandem. Por exemplo, a tag padrão `{% comment %}` esconde tudo até `{% endcomment %}`. Para criar uma tag de template coo esta, use `parser.parse()` na sua função de compilação.

Aqui como uma tag `{% comment %}` simplificada pode ser implmentada:

    def do_comment(parser, token):
        nodelist = parser.parse(('endcomment',))
        parser.delete_first_token()
        return CommentNode()

    class CommentNode(template.Node):
        def render(self, context):
            return ''

Nota

The actual implementation of `{% comment %}` is slightly different in that it allows broken template tags to appear between `{% comment %}` and `{% endcomment %}`. It does so by calling `parser.skip_past('endcomment')` instead of `parser.parse(('endcomment',))` followed by `parser.delete_first_token()`, thus avoiding the generation of a node list.

`parser.parse()` recebe uma tupla de nomes de blocos de tags para parsear. Ele retorna uma instância de `django.template.NodeList`, que é uma lista de todos os objetos `Node` que o analisador encontrou “antes” que tenha encontrado qualquer nome de tags na tupla.

Em `"nodelist = parser.parse(('endcomment',))"` no exemplo acima, `nodelist` é uma lista de todos os nós entre o``{% comment %}`` e `{% endcomment %}`, sem contar os próprios `{% comment %}` e `{% endcomment %}`.

Depois que `parser.parse()` é chamado, o analisaor sintático ainda não “consumiu” a tag `{% endcomment %}`, então o código precisa chamar explicitamente o `parser.delete_first_token()`.

`CommentNode.render()` simplesmente retorna uma string vazia. Qualquer coisa entre `{% comment %}` e `{% endcomment %}` é ignorado.

### Analisando sintaticamente até um outro bloco da tag, e armazenando seu conteúdo.

No exemplo anterior, `do_comment()` descartou tudo entre``{% comment %}`` e `{% endcomment %}`. Ao invés de fazer isso, é possível fazer alguma coisa com o código que está dentro do bloco de tags.

Por exemplo, aqui uma tag de template, `{% upper %}`, que coloca todas as letras em maiúsculo de tudo entre ela e `{% endupper %}`.

Uso:

    {% upper %}This will appear in uppercase, {{ your_name }}.{% endupper %}

Como no exemplo anterior, usaremos `parser.parse()`. Mas agora, passamos o `nodelist` resultante para o `Node`:

    def do_upper(parser, token):
        nodelist = parser.parse(('endupper',))
        parser.delete_first_token()
        return UpperNode(nodelist)

    class UpperNode(template.Node):
        def __init__(self, nodelist):
            self.nodelist = nodelist
        def render(self, context):
            output = self.nodelist.render(context)
            return output.upper()

O único conceito novo aqui é o `self.nodelist.render(context)` no `UpperNode.render()`.

Para mais exemplos de renderização mais complexas, veja o código fonte da `{% for %}` em `django/template/defaulttags.py` e `{% if %}` em `django/template/smartif.py`.