Как заставить шаблон расширить другой? - PullRequest
3 голосов
/ 09 июля 2010

У меня есть несколько шаблонов, которые я строю из данных, хранящихся в моей БД:

my_template = Template(string_data)

Теперь я хочу, чтобы этот шаблон расширил другой (также хранящийся в виде текста в БД). Как я могу это сделать? Ищу что-то вроде:

my_template.base = other_template

Или каков бы ни был синтаксис. Не могу найти документацию по этому вопросу.


Я вижу template.nodelist в источнике; могу ли я добавить какой-нибудь узел extends?


Добавлена ​​награда ... будет предоставлена ​​первому человеку, который скажет мне, как это сделать, не взломав ядро ​​django.

Ответы [ 5 ]

3 голосов
/ 30 июля 2010

Не нужно взламывать ядро ​​Django.Создать собственный загрузчик шаблонов, как рекомендует Игнасио, довольно просто.Вам просто нужно создать подкласс django.template.loader.BaseLoader и реализовать метод load_template_source.Это просто берет строку для имени шаблона, которую вы можете просто использовать для поиска элемента в базе данных и возврата строки.

В вашем случае, так как у вас есть два элемента шаблона в одномdb row, вы можете захотеть сделать что-то, чтобы указать это в теге extends:

{% extends "myinstance.html_version" %}

и просто разделить это на load_template_source:

def load_template_source(self, template_name, template_dirs=None):
    name, field = template_name.split('.')
    tpl = TemplateModel.objects.get(name=name)
    return getattr(tpl, field)

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

Редактировать после комментария Я до сих пор не совсем понимаю, почему, но если все, что вы хотите сделать, это выбратьдинамически расширять шаблон, почему бы просто не вставить его в текстовый шаблон перед обработкой?

    tpl_string = get_template_from_wherever()
    extender = '{% extends "%s" %}' % template_name_to_extend
    tpl = Template(extender + tpl_string)

Все еще хак, но, вероятно, гораздо меньше, чем копаться во внутреннем наследовании шаблонов.

2 голосов
/ 02 августа 2010

Чтобы сформулировать свою проблему, вы хотите:

  1. Возьмите текст, который вы уже получили в строке (потому что вы загрузили его из базы данных),
  2. Возьмите больше текста, который вы собираетесь загрузить в строку (потому что вы знаете, откуда его загрузить),
  3. Сделать родительский шаблон из второй строки,
  4. Сделать дочерний шаблон из первой строки,
  5. Установить родительский шаблон (из первой строки) как родительский шаблон (из второй строки),
  6. Оценить дочерний шаблон.
  7. Самое главное, вы хотите, чтобы в дочернем шаблоне не было ничего похожего на {% extends ...%}, потому что ... почему?
  8. И, наконец, вы хотите сделать это без взлома ядра Django .

Краткий ответ:

Не возможно. Из коробки Джанго не будет делать то, что вы просите.

Длинный ответ:

Вся концепция наследования шаблонов в Django реализована через тег extends. Точнее, это реализовано с помощью класса ExtendsNode модуля django.template.loader_tags, который создается при разборе тега extends. Когда вы создаете Template (), он анализирует исходную строку и создает список узлов (хранится в списке узлов шаблона, как вы уже отмечали ранее). Позже вы можете визуализировать шаблон, используя любой контекст, который вам нравится, сколько угодно раз.

Грубо говоря, рендеринг работает, вызывая render () для каждого узла в списке узлов. Если первым узлом в списке узлов шаблона является ExtendsNode (а должен быть первым узлом), то происходит волшебство наследования шаблона. Когда создается ExtendsNode, ему присваивается список узлов шаблона и имя родителя (в виде строки (parent_name) или выражения (parent_name_expr). Когда визуализируется ExtendsNode, он будет использовать свой метод get_parent () для вызова get_template (parent_name) ), который вызовет механизм загрузчика шаблонов для загрузки родительского шаблона. Как только у него будет родительский шаблон, метод ExtendsNode :: render () будет использовать магию наследования шаблона.

Не стесняйтесь проверить код самостоятельно .

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

  1. Создайте класс SpecialExtendsNode (ExtendsNode), переопределяя метод __init__ и метод get_parent.
  2. После создания шаблона из дочерней строки создайте экземпляр своего подкласса, инициализированный из родительского шаблона.
  3. Вставьте ваш экземпляр SpecialExtendsNode в заголовок списка узлов дочернего шаблона.
  4. Молитесь, чтобы разработчики Django ничего не изменили.

Просто чтобы упростить вам задачу, вот ваш класс:

class SpecialExtendsNode(ExtendsNode):

    def __init__( self, nodelist, parent, name ):
        self.myparent = parent
        ExtendsNode.__init__( self, nodelist, name, None, None )

    def get_parent( self ):
        return self.myparent

И код для его использования будет выглядеть так:

parent = Template( parent_string )
child = Template( child_string )
hack = SpecialExtendsNode( child.nodelist, parent, "parent name" )
child.nodelist.insert( 0, hack )
output = child.render( context )

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

Код, который я написал здесь, не проверяется на наличие ошибок и был написан для Django 1.2.Хотя я не тестировал его, я на 99% уверен, что он будет работать на Django 1.2.Я понятия не имею, будет ли он работать на любой другой версии Django.С другой стороны, помимо предоставления исходного кода, разработчики Django не документировали внутреннюю часть своего процессора шаблонов, кроме как для обеспечения документированных интерфейсов для написания новых тегов и фильтров шаблонов и документированного интерфейса для написания загрузчиков шаблонов (особенно упоминаниясценарий загрузки шаблона из базы данных).Это означает, что есть разумный случай, когда когда-нибудь разработчики Django могут переписать или значительно изменить механизм расширения шаблона.Если они это сделают, я на 100% гарантирую, что этот код сломается.Зачем?Потому что это хак.Вот как выглядит взломавший ядро ​​Django .Он будет работать в течение дня, недели или даже месяцев, но рано или поздно вы (или программист, который придет за вами) обновится с Django 1.2 до более поздней версии, и тогда он сломается.И когда он сломается, я не смогу помочь вам, и разработчики Django все спросят: почему вы просто не написали загрузчик шаблонов?

Теперь скажите мнечто включает в себя больше взлома ядра Django - написание загрузчика шаблонов, который документирован и поддерживается разработчиками, или что я только что описал?

1 голос
/ 09 июля 2010

Я думаю, вам нужно создать подкласс django.template.loader_tags.ExtendNode и переопределить его get_parent метод, чтобы вы могли использовать там свой собственный get_template! Тогда вы сможете добавить ExtendNode к вашему template.nodelist, но также помните, что он должен быть первым!

1 голос
/ 09 июля 2010

К сожалению, вам понадобится написать собственный шаблонный загрузчик для чтения базы данных.Для этого обычно используется тег шаблона {% extends %}, но он откладывает задачу фактической загрузки шаблонов в загрузчики.

0 голосов
/ 06 августа 2010
from app.models.misc import EmailTemplate
from django.template import TemplateDoesNotExist
from django.template.loader import BaseLoader

class Loader(BaseLoader):
    is_usable = True
    def load_template_source(self, template_name, template_dirs=None):
        try:
            key, ext = template_name.split('.')
            attr = {
                'html': 'html_content',
                'txt': 'text_content',
            }[ext]
            tpl = EmailTemplate.objects.get(key=key)
            return (getattr(tpl, attr), repr(tpl))
        except:
            raise TemplateDoesNotExist

Действительно трудно написать, когда вы не можете найти обновленную документацию: \

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