Запросить шаблон для нужных ему переменных? - PullRequest
12 голосов
/ 04 декабря 2009

Я хотел бы иметь возможность создавать экземпляр шаблона из файла (предположительно, используя django.template.loader.get_template (filename)), а затем определять набор переменных, которые должны быть определены в любом контексте, в котором он передается. .

Я думал, что будет метод для объекта Template, но, похоже, его нет.

Я прочитал документы, и самое близкое, что я нашел, было это:

http://docs.djangoproject.com/en/1.0/topics/templates/#using-the-built-in-reference

, который предлагает перейти в интерфейс администратора, чтобы увидеть все переменные, связанные с данным представлением.

Я не хочу проходить через интерфейс администратора, потому что я хочу сделать это программно - я пытаюсь писать тесты.

Я использую версию Django (1, 0, 2, 'final', 0)

Обновлен:

Я попробовал ответ synack и обнаружил, что (с заменой filter_expression.token на filter_expression.var, чтобы получить фактическое имя переменной без тегов и т. Д.) Он вернул переменные, которые локально определены в шаблоне, не работал для переменных, которые определены в родительском объекте, который он расширяет.

Например, предположим, у меня есть шаблоны в двух файлах:

toyparent.html:

{%block base_results%}
Django is {{adjective}}
{%endblock base_results%}

toychild.html:

{% extends "toyparent.html" %}

{%block base_results%}
    {{block.super}}
    I {{verb}} it.
{%endblock base_results %}

И я загружаю дочерний шаблон:

>>> toy=django.template.loader.get_template('toychild.html')

Это правильно отображает:

>>> toy.render(django.template.Context(dict(adjective='cool',verb='heart')))
u'\n    \nDjango is cool\n\n    I heart it.\n\n'

Но я не могу получить две переменные из него:

>>> v=toy.nodelist.get_nodes_by_type(VariableNode)
>>> for k in v: print k.filter_expression.var
...
block.super
verb

1 Ответ

20 голосов
/ 04 декабря 2009

Вы можете визуально проверить шаблон и наблюдать наличие любых объектов «Переменного узла» в списке узлов этого шаблона:

>>> from django.template import Template, Context
>>> t = Template("Django is {{ adjective }} and I {{ verb }} it.")
>>> t.nodelist
[<Text Node: 'Django is '>, <Variable Node: adjective>, <Text Node: ' and I '>, <Variable Node: verb>, <Text Node: ' it.'>]

Они относятся к типу VariableNode, который является классом, который можно напрямую импортировать для использования в сравнениях. Любой экземпляр Node имеет метод get_nodes_by_type(), который можно вызывать для списка узлов, который возвращает все узлы этого типа для шаблона. Пример:

>>> from django.template import VariableNode
>>> varnodes = t.nodelist.get_nodes_by_type(VariableNode)
>>> varnodes
[<Variable Node: adjective>, <Variable Node: verb>]

Итак, теперь у вас есть список переменных для шаблона. Для этого потребуется сделать еще один шаг, чтобы извлечь действительное имя каждой переменной, не выполняя глупых трюков с разрезанием строк на их repr именах.

Само имя переменной хранится в filter_expression.token для каждого VariableNode:

>>> varnodes[0].filter_expression.token
u'adjective'

И вот простое понимание списка дает нам все имена переменных для шаблона:

>>> template_vars = [x.filter_expression.token for x in varnodes]
>>> template_vars
[u'adjective', u'verb']

Итак, не самое простое решение, но если есть лучший способ, я не знаю об этом.

Бонус: Функция !!

from django.template import VariableNode
def get_template_vars(t):
   varnodes = t.nodelist.get_nodes_by_type(VariableNode)
   return [x.filter_expression.token for x in varnodes]

Хорошо, все не так сложно!

Последующее редактирование: получение переменных из родительских шаблонов

(Это продолжение использует информацию из обновленного вопроса).

Вот где он действительно становится сложным, потому что список узлов игрушечного шаблона - это один ExtendsNode (в данном случае).

>>> toy.nodelist
[<ExtendsNode: extends "mysite/toyparent.html">]

Я бы предположил, что в больших шаблонах может быть несколько ExtendsNode объектов. В любом случае, если вы осмотрите ExtendsNode и извлечете из него родительский шаблон, вы сможете обращаться с родительским шаблоном так же, как в моем исходном примере:

>>> enode = toy.nodelist[0]
>>> enode.parent_name
u'mysite/toyparent.html'
>>> parent = enode.get_parent(enode.parent_name)
>>> parent
<django.template.Template object at 0x101c43790>
>>> parent.nodelist.get_nodes_by_type(VariableNode)
[<Variable Node: adjective>]

И ваша adjective переменная извлечена из родительского шаблона. Чтобы выполнить тест по ExtendsNode, вы можете импортировать класс из django.template.loader_tags:

>>> from django.template.loader_tags import ExtendsNode
>>> ext = toy.nodelist.get_nodes_by_type(ExtendsNode)
>>> ext
[<ExtendsNode: extends "mysite/toyparent.html">]

Итак, вы могли бы провести несколько тестов с шаблонами на наличие ExtendsNode и вернуться назад к родительскому шаблону и по отдельности получить эти имена переменных. Тем не менее, это начинает казаться банкой червей.

Например, если вы должны были сделать это:

>>> toy.nodelist.get_nodes_by_type((ExtendsNode, VariableNode))
[<ExtendsNode: extends "mysite/toyparent.html">, <Variable Node: block.super>, <Variable Node: verb>]

Теперь у вас есть объекты ExtendsNode и VariableNode, и это только начинает сбивать с толку. Что мы будем делать тогда? Пытаемся ли мы игнорировать переменные block, полученные из таких тестов? Я не знаю !!

В любом случае, это та информация, которую вы хотели, но я не думаю, что это практическое решение. Я настаиваю на том, что есть еще лучший способ. Возможно, стоит разобраться в том, что вы пытаетесь решить, и посмотреть, есть ли другой подход, который вы можете использовать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...