嵌套的 Django 模板

Posted

技术标签:

【中文标题】嵌套的 Django 模板【英文标题】:Nested django templates 【发布时间】:2011-08-20 10:21:52 【问题描述】:

这似乎是一件非常基本的事情,但尽管我已经使用 Django 大约一年了,但我从未遇到过这种情况。

在很多模板/网络框架中,模板继承的工作方式有点不同,因为它通常表现得更像包装器,所以如果你有 childtemplate.html、parenttemplate.html 和 grandparenttemplate.html,那么最终渲染通常看起来像:

grandparent header
    parent header
        child header
        child content
    parent content
    parent footer
grandparent content
grandparent footer

这并不是它在 Django 中的工作方式,但我想知道如何实现它。

具体来说,我有我的“子”模板,假设它是foo.htmlfoo.html 可选获取变量parent_template 或默认为“base.html”

% extends parent_template|default:"base.html" %

% block content %
I am a foo and my title is  foo.title 
% endblock content %

所以,这就是我遇到障碍的地方。如果parent_template 是一个模板,该模板应该包装foo.html 的内容,然后将结果放入base.html

% extends "base.html" %

% something_magical_here %
<div>parent header</div>
# content of foo.html
<div>parent footer</div>
% end_something_magical_here %

然后在base.html:

<html>
... snip ...
<div id="content">
% something_else_magical %
# content of parent_template rendering, or just foo.html if no parent_template given
% end_something_else_magical %

应该呈现为

<html>
... snip ...
<div id="content">
<div>parent header</div> 
I am a foo and my title is Bar
<div>parent footer</div>

如果设置了 parent_template 并且

<html>
... snip ...
<div id="content">
I am a foo and my title is Bar

如果不是。

我希望我的问题很清楚:我需要(可选地)将模板包装在父模板中,然后将结果发送到base.html 模板。

通常,这样的事情可能会起作用:

#foo.html
% extends "parent.html" %
% block child_content %
I am a foo and my title is  foo.title 
% endblock child_content %

#parent.html
% extends "base.html" %

% block content %
parent header
% block child_content %% endblock child_content %
parent content
parent footer

#base.html
base header
% block content %% endblock content %
base content
base footer

但是,由于 parent_template 可能是空白的,所以有时 base.html 会得到 child_content 块,而不是 content 块。

另外,我希望能够做到这一点而不必创建一堆子块(如果我决定 foo 应用程序应该有自己的 /foo/base.html 然后调用 /base.html 怎么办) ?

有什么想法吗?

【问题讨论】:

【参考方案1】:

extends 模板标签可以接受可变参数。

所以:

base.html
    % block content %
        <p>BASE</p>
    % endblock %

parent.html
    % extends "base.html" %

    % block content %
         block.super 
        <p>PARENT</p>
    % endblock %

foo.html
    % extends ext_templ %

    % block content %
         block.super 
        <p>FOO</p>
    % endblock %

使用基础:

return render_to_response('foo.html', 'ext_templ':'base.html')

给你:

<p>BASE</p>
<p>FOO</p>

使用父母:

return render_to_response('foo.html', 'ext_templ':'parent.html')

给你:

<p>BASE</p>
<p>PARENT</p>
<p>FOO</p>

编辑:

解决此问题以获取嵌套块的一种方法是:

base.html
    % block content %
        % block top %
            <p>BASE START</p>
        % endblock %

        % block bot %
            <p>BASE END</p>
        % endblock %
    % endblock %


parent.html
    % extends "base.html" %

    % block top %
         block.super 
        <p>PARENT</p>
    % endblock %

    % block bot %
        <p>PARENT</p>
         block.super 
    % endblock %

foo.html
    % extends ext_templ %

    % block top %
         block.super 
        <p>FOO</p>
    % endblock %

    % block bot %
        <p>FOO END</p>
         block.super 
    % endblock %

我能想到的另一种方法是用% if ext_templ == 'parent.html' % 标签包装这些块,但这似乎不是很干。我也很想看看其他人对嵌套块的反应。

【讨论】:

我知道发送可变参数的能力,这就是我正在做的事情。我需要&lt;p&gt;BASE START&lt;/p&gt;&lt;p&gt;PARENT START&lt;/p&gt;&lt;p&gt;FOO&lt;/p&gt;&lt;p&gt;PARENT END&lt;/p&gt;&lt;p&gt;BASE END&lt;/p&gt; 所以 block.super 不会删减它,因为它只会将内容放在顶部。 我赞成你的回答,因为我认为这个想法很有趣,但它仍然不是一个完整的答案。我肯定希望看到其他人的回应,如果有的话。 :) django 需要理清它的多重模板继承,否则你应该如何为你的网站获得一个外观和感觉。因此,我的网站看起来不是很干燥【参考方案2】:

我有三个模板:gparent、parent 和 gchild。然后我测试了 gparent 和 gchild 如下:

gparent 具有以下块 hn 标记。 gchild 扩展了 gparent。没有对父级的引用。

% block hn %              
Can you see me?     # 1  naked text in the html, treated as a string.
  "No, I cant see you."     # 2 A string literal in the variable template brace.
% endblock hn %

标签之间的这两行都显示在屏幕上的孩子身上。当后者不是字符串时,Django 会抛出解析错误。这是因为在双花括号内,Django 期待一个变量,或者它可以评估的类似字符串文字。

当我给gchild添加一个block hn和这个内容时,gchild的block hn内容就是我看到的。

% block hn %
Now I have my own hn block                      
% endblock hn %
                            

然后我重复了这个测试,将 gchild 的块 hn 留在原地,但带走了内容:

% block hn %          
% endblock hn %                                   

一个,但存在 gchild 上的块 hn 阻止(覆盖)gparent 的块 hn 内容。

对于下一个测试,我在 gparent 和 gchild 之间插入了 parent。现在 parent 扩展 gparent,gchild 扩展 parent。

%  block metadata %
 "You must eat your metadata to grow big and strong" 
% endblock metadata %

Parent 现在有这个块元数据标签,它既不存在于 gparent 也不存在于 gchild。 此内容未显示。

接下来,我将块元数据嵌套在父块 hn 中。 gparent 仍然有我们刚才从块 hn 测试的两个字符串。 gchild 有一个空块 hn。

和以前一样,什么都没有显示。

我现在将从 gchild 中删除块 hn:

You must eat your metadata to grow big and strong

因此,您可以添加一个在早期模板生成中不存在的新块标记,只要它完全嵌套在祖先确实定义的可用块中。

三明治生成然后会将新标签及其内容传递给孩子,如果孩子不阻止(覆盖)它,它将显示它。

请记住,文档将标签之间的内容描述为要填补的漏洞。如果孩子没有标签,则该洞由父母填补。这就是使父级的内容成为默认值的原因。这也是为什么大多数基本模板都包含您想要在整个站点中使用的页眉、页脚、导航和样式的原因。但是在孩子身上贴上相同的标签时,孩子自己正在填补这个洞。同样,这就是为什么子级可以拥有自己的块标题标签,即使它嵌套在 html 内,通常位于父块标题内,或者您选择的任何名称。

当我第一次学习 Django 时,我真的很挣扎,因为我一直想做一些疯狂的事情,比如

% block first %
% block second %
% endblock first %
% endblock second %

这在任何地方都行不通。

【讨论】:

【参考方案3】:
    base.html
% block content %
  <p>Grand Parent file</p>
% endblock %
    parent.html
% extends 'base.html' %

% block content %
    % include 'grandchild1.html' %
    % include 'grandchild2.html' %
% endblock %

3.1。孙子1.html

<div>Hello I'm grandchild 1</div>

3.2 孙子1.html

<div>Hello I'm grandchild 2</div>

这样您可以嵌套到任何级别。将每个组件分部分写入单独的 .html 文件中。 将它们包含到 parent.html 或任何其他文件中。

【讨论】:

以上是关于嵌套的 Django 模板的主要内容,如果未能解决你的问题,请参考以下文章

Django 模板 - 嵌套字典迭代

Django模板访问嵌套数据

如何在 Django 模板中嵌套或联合使用两个模板标签?

尝试遍历 django 模板中的嵌套字典

Django 多级模板扩展和嵌套块

为啥 Django 模板循环嵌套了我的 div?