Подтвердить что ты не робот

Запросить шаблон для требуемых переменных?

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

Я думал, что будет существовать метод в объекте Template, но, похоже, этого не происходит.

Я прочитал документы, и ближайший я нашел следующее:

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

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

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

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

Обновлено:

Я попробовал синхронизировать ответ и обнаружил, что (с заменой 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
4b9b3361

Ответ 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, возвращаемые из таких тестов? Я не знаю!!

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