Python Django-在呈现模板之前呈现模板标记

Python Django-在呈现模板之前呈现模板标记,python,django,templates,Python,Django,Templates,我有一个问题,我不太确定如何解决。我有一个模板,它将呈现一段文本,该文本本身将包含一个要动态更新的模板标记 <ul> {% for section in sections %} <li>{{ section.content | safe }}</li> {% endfor %} </ul> 然后,我需要动态更新节.content中的{{document.customer}标记。该标记在模板中可以很好地渲染,但不能作为也要渲染的各个

我有一个问题,我不太确定如何解决。我有一个模板,它将呈现一段文本,该文本本身将包含一个要动态更新的模板标记

<ul>
  {% for section in sections %}
    <li>{{ section.content | safe }}</li>
  {% endfor %}
</ul>
然后,我需要动态更新
节.content中的
{{document.customer}
标记。该标记在模板中可以很好地渲染,但不能作为也要渲染的各个部分的一部分。如何在模板中的节中呈现模板变量

我尝试用
{%include“display\u lld\u sections.html”替换上面的内容,替换为sections=sections document=document%}
但这没有什么区别,因为我认为这只是将问题转移到另一个模板。我也看不出写一个自定义标记会有什么帮助,因为它仍然只对部分有效,而不是对部分中的内容有效,对吗

我还尝试了使用
with
语句:

<ul>
  {% for section in sections %}
    {% with document=document %}
      <li>{{ section.content | safe }}</li>
    {% endwith %}
  {% endfor %}
</ul>

虽然不是这样,但我怀疑解决这个问题的方法。这是否需要在我的视图或模型中使用代码来完成,而不是在我的模板中完成?

您应该将
部分。内容
包装到模板中,并使用
include
标记将其包含,如下所示:

lookup = re.compile(r'{{ *(\w+) *}}')
def interpolate(text, context):
    replacer = lambda m: context.get(m.group(1), '')
    return lookup.sub(replacer, text)

def in_your_view(self, whatever):
    # some stuff
    section_context = {
        "customer": document.customer,
        "foo": "bar",
    }
    for section in sections:
        section.interpolated = interpolate(section.section, section_context)
{%include section.content_template%}

比方说,如果您的节是django模型实例,请将此属性添加到该模型中:

    @property
    def content_template(self):
        from django.template.backends.django import Template
        return Template(self.content)

当然,您可以为模板动态选择引擎,但在其他引擎中,包括模板对象可能无法工作。

这取决于您需要的多功能性级别

  • 如果内容实际上可以包含任何类型的模板功能,那么您将别无选择,只能将其作为模板。看看格温布利德的答案吧。但也有一些缺点:

    • 主要缺点是Django不会缓存这些模板,因此每次都必须编译它们,这可能会对性能产生重大影响
    • 此外,如果
      内容可能来自不受信任的来源,请记住,将其作为模板将使其能够访问大量内部数据(上下文、上下文处理器公开的任何内容,如站点设置、所有类型的标记等)。如果我用内容制作一个部分:
      Hehe,我得到了你的{{{settings.DATABASES.default.PASSWORD}
  • 但是,如果您只需要替换一小部分已知变量,您可以在视图中进行简单的字符串替换,查找
    {{document.customer}
    ,并替换为值

    如果你走这条路,也许你应该简化一点。我会这样做:

    lookup = re.compile(r'{{ *(\w+) *}}')
    def interpolate(text, context):
        replacer = lambda m: context.get(m.group(1), '')
        return lookup.sub(replacer, text)
    
    def in_your_view(self, whatever):
        # some stuff
        section_context = {
            "customer": document.customer,
            "foo": "bar",
        }
        for section in sections:
            section.interpolated = interpolate(section.section, section_context)
    
    这将用customer替换
    {{customer}}
    ,用
    bar替换
    {{foo}}
    ,而不做任何模板工作。它是有意限制的,因此它不会提供对任何数据的访问,而是来自上下文的内容。而且它没有解析模板对性能的影响

    现在您只需在视图中输出̀
    {{section.interpolated}}
    ,就完成了


什么是
章节内容
?其他模板的结果?还是数据库中的一些文本?节是一个模型,而内容是该模型的一个字段。因此,当我调用一个部分查询集时,section.content是查询集中每个部分的内容字段。哇,谢谢。这需要考虑很多。老实说,我没有想到向用户开放模板语言会带来安全隐患。我想我将继续替换视图中特定的、已知的值。我的python知识仍然有限,因此我将花时间理解您的代码。此视图是否会将
section.interpolated
添加到
sections
中,因此在我的视图中,我仍然使用
返回渲染(请求,'template.html',{'sections':sections}
,然后在我的模板中
{%for sections%}
  • {section.interpolated | safe}
  • {%endfor%}
    ?谢谢。是的,你就是这样做的。至于安全方面的考虑,请小心使用
    |safe
    ,这会使Django假设变量中的任何内容都是安全的,这可能是一个问题,例如,
    标记只会按原样被注入。再次感谢@spectras终于抽出时间来实现它,它的工作非常有魅力。
    lookup = re.compile(r'{{ *(\w+) *}}')
    def interpolate(text, context):
        replacer = lambda m: context.get(m.group(1), '')
        return lookup.sub(replacer, text)
    
    def in_your_view(self, whatever):
        # some stuff
        section_context = {
            "customer": document.customer,
            "foo": "bar",
        }
        for section in sections:
            section.interpolated = interpolate(section.section, section_context)