我有一些模板,我正在根据我存储在数据库中的一些数据构建:
my_template = Template(string_data)
现在我希望该模板扩展另一个模板(也作为文本存储在数据库中)。我怎样才能做到这一点?寻找类似的东西:
my_template.base = other_template
或者无论语法是什么。找不到相关文档。
我在源中看到template.nodelist;我可以预先添加某种扩展节点吗?
添加赏金......将授予第一个可以告诉我如何在不破坏django核心的情况下执行此操作的人。
答案 0 :(得分:3)
无需破解Django的核心。像Ignacio推荐的那样,创建自己的模板加载器非常简单。您只需要子类django.template.loader.BaseLoader
,并实现load_template_source
方法。这只需要一个字符串作为模板名称,您只需使用它来查找数据库中的项目并返回字符串。
在您的情况下,由于您在单个数据库行中有两个模板元素,您可能想要在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
元组中指定此模板加载器。
评论后编辑我仍然不明白为什么,但如果您只想选择要动态扩展的模板,为什么不在处理前将其插入文本模板中?
tpl_string = get_template_from_wherever()
extender = '{% extends "%s" %}' % template_name_to_extend
tpl = Template(extender + tpl_string)
仍然是一个黑客攻击,但可能远不及使用模板继承的内部结构。
答案 1 :(得分:2)
要重述您的问题,您需要:
{% extends ...%}
之类的内容,因为......为什么?简答:
不可能。开箱即用,Django不会做你想要的。
答案很长:
Django中模板继承的整个概念是通过extends
标记实现的。更准确地说,它是通过django.template.loader_tags模块的ExtendsNode类实现的,该模块是在解析extends
标记时创建的。当您创建Template()时,它会解析其源字符串,并创建一个节点列表(存储在模板的节点列表中,如前所述)。在以后的日子里,您可以根据需要使用您喜欢的任何上下文来渲染模板。
粗略地说,渲染的工作原理是在nodelist中的每个节点上调用render()。如果模板的nodelist中的第一个节点是ExtendsNode(并且必须是第一个节点),那么模板继承魔法就会发生。创建ExtendsNode时,会给出模板的nodelist和父名称(作为字符串(parent_name)或表达式(parent_name_expr)。)呈现ExtendsNode时,它将使用其get_parent()方法调用get_template(parent_name) ),它将调用模板加载器机制来加载父模板。一旦有了父模板,ExtendsNode :: render()方法将起到模板继承的神奇作用。
随时查看code yourself。
为了避免使用模板加载器,您必须执行以下操作:
__init__
方法和get_parent
方法。为了方便你,这是你的班级:
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 的核心 - 编写模板加载器,开发人员记录并支持,或者我刚刚描述的内容?
答案 2 :(得分:1)
不幸的是,您需要编写自己的template loader来读取数据库。 {% extends %}
模板标记通常用于此目的,但它将实际加载模板的任务推迟到加载器。
答案 3 :(得分:1)
我认为您需要继承django.template.loader_tags.ExtendNode
并覆盖其get_parent
方法,以便您可以在那里使用自己的get_template
!然后你应该可以将ExtendNode
添加到template.nodelist
,但也要注意它必须是第一个!
答案 4 :(得分:0)
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
当您找不到更新的文档时真的很难写:\