Ответ 1
Вы можете визуально проверить шаблон и наблюдать за наличием каких-либо объектов "Variable Node" в этом списке узлов:
>>> 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
, возвращаемые из таких тестов? Я не знаю!!
В любом случае, это информация, которую вы хотели, но я не думаю, что это практическое решение. Я настаиваю на том, что есть, вероятно, лучший способ. Возможно, стоит взглянуть на то, что вы пытаетесь решить, и посмотреть, есть ли другой подход, который вы можете предпринять.