要重申您的问题,您希望:
- 获取您已经在字符串中获取的文本(因为您是从数据库加载的),
- 将您要加载到字符串中的更多文本(因为您知道从哪里加载),
- 用第二个字符串制作父模板,
- 从第一个字符串中创建一个子模板,
- 将子模板的父模板(从第一个字符串)设置为父模板(从第二个字符串),
- 评估子模板。
- 最重要的是,您希望避免在子模板中包含
{% extends ...%} 之类的内容,因为...为什么?
- 最后,您希望在不破解 Django 核心的情况下做到这一点。
简答:
不可能。开箱即用,Django 不会按照您的要求进行操作。
长答案:
Django中模板继承的整个概念是通过extends标签实现的。更准确地说,它是通过 django.template.loader_tags 模块的 ExtendsNode 类实现的,该类是在解析 extends 标签时创建的。当您创建 Template() 时,它会解析其源字符串,并创建节点列表(存储在模板的节点列表中,如前所述)。以后,您可以使用任何您喜欢的上下文来渲染模板,并且可以多次渲染。
大致上,渲染通过在节点列表中的每个节点上调用 render() 来工作。如果模板节点列表中的第一个节点是 ExtendsNode(并且它必须是第一个节点),那么模板继承魔法就会发生。当ExtendsNode被创建时,它被赋予模板的节点列表,和一个父名字(可以是字符串(parent_name)或表达式(parent_name_expr)。当ExtendsNode被渲染时,它会使用它的get_parent()方法来调用get_template(parent_name) ),它将调用模板加载器机制来加载父模板。一旦有了父模板,ExtendsNode::render() 方法就会发挥模板继承的魔力。
随时查看code yourself。
为了避免使用模板加载器,您必须执行以下操作:
- 创建一个类 SpecialExtendsNode(ExtendsNode),覆盖
__init__ 方法和 get_parent 方法。
- 从子字符串创建模板后,创建子类的实例,从父模板初始化。
- 将您的 SpecialExtendsNode 实例插入子模板节点列表的头部。
- 祈祷这一切都不会被 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 的核心——编写一个模板加载器,由开发人员记录和支持,还是我刚才描述的?