使用标准库可以在Go中嵌套模板吗?


87

如何在python运行时中获取类似于Jinja的嵌套模板。TBC的意思是,我如何从基本模板继承一堆模板,就像Jinja / django-templates一样,以基本模板的块形式进行归档。是否可以仅html/template在标准库中使用。

如果那是不可能的,那我有什么选择。胡子似乎是一种选择,但是我会不会错过那些html/template诸如上下文相关的转义等漂亮的微妙功能?还有什么其他选择?

(环境:Google App Engin,Go runtime v1,Dev-Mac OSx lion)

谢谢阅读。

Answers:


132

是的,有可能。Ahtml.Template实际上是一组模板文件。如果执行该集中定义的块,则该块有权访问该集中定义的所有其他块。

如果您自己创建此类模板集的映射,则基本上具有Jinja / Django提供的灵活性。唯一的区别是html / template包无法直接访问文件系统,因此您必须自己解析和编写模板。

考虑下面的示例,其中有两个不同的页面(“ index.html”和“ other.html”)都继承自“ base.html”:

// Content of base.html:
{{define "base"}}<html>
  <head>{{template "head" .}}</head>
  <body>{{template "body" .}}</body>
</html>{{end}}

// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}

// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}

以及以下模板集图:

tmpl := make(map[string]*template.Template)
tmpl["index.html"] = template.Must(template.ParseFiles("index.html", "base.html"))
tmpl["other.html"] = template.Must(template.ParseFiles("other.html", "base.html"))

您现在可以通过调用来呈现“ index.html”页面

tmpl["index.html"].Execute("base", data)

您可以通过调用来渲染“ other.html”页面

tmpl["other.html"].Execute("base", data)

通过一些技巧(例如,模板文件的命名约定一致),甚至可以tmpl自动生成地图。


3
是否可以使用默认数据,例如“ head”?
gregghz 2012年

18
我将在此处添加,以便渲染我必须调用的实际模板tmpl["index.html"].ExecuteTemplate(w, "base", data)
hermansc

base.html被解析并存储两次。您也可以像golang.org/pkg/text/template/#example_Template_share
Maarten O

3
将数据传递到嵌套模板时遇到问题。来自的数据{{ .SomeData }}将不会显示在内部模板中。外部工程。
0xAffe

它很重要,如果template.ParseFiles("index.html", "base.html")template.ParseFiles("base.html", "index.html")
shackra

10

请注意,在执行基本模板时,必须将值向下传递到子模板,这里我只是传递“。”,以便所有内容都向下传递。

模板之一显示{{。}}

{{define "base"}}
<html>
        <div class="container">
            {{.}}
            {{template "content" .}}
        </div>
    </body>
</html>
{{end}}

模板两个显示{{.domains}}并传递给父级。

{{define "content"}}
{{.domains}}
{{end}}

请注意,如果我们使用{{template“ content”。}}而不是{{template“ content”。}},则无法从内容模板访问.domains。

DomainsData := make(map[string]interface{})
    DomainsData["domains"] = domains.Domains
    if err := groupsTemplate.ExecuteTemplate(w, "base", DomainsData); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }

5
传递模型是我一直坚持的细节。;)谢谢
Patrick Patrick

1
我也是-花了点时间才弄明白了:)
罗伯特·金(Robert King)

1
什么!我不敢相信{{template}}占位符末尾的小圆点有太多含义!为什么在教程甚至Go的官方文档中都没有提到这个?我很惊讶...但也很高兴找到您的答案!非常感谢,现在我的带有多层嵌套的模板可以很好地工作!
Gwyneth Llewelyn

确实,我正在尝试找出同一件事!
devforfu

5

曾经与其他模板包一起工作过,现在有一天我主要使用标准html / template包,我想我很天真地不欣赏它提供的简单性和其他优点。我使用非常相似的方法对接受的答案进行了以下更改

您不需要使用其他base模板来包装布局,为每个已解析的文件创建一个模板块,因此在这种情况下它是多余的,我也想使用go的新版本中提供的block动作,这样您就可以如果您没有在子模板中提供一个模板,则默认为块内容

// base.html
<head>{{block "head" .}} Default Title {{end}}</head>
<body>{{block "body" .}} default body {{end}}</body>

您的页面模板可以与

// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}

// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}

现在执行模板,您需要像这样调用它

tmpl["index.html"].ExecuteTemplate(os.Stdout, "base.html", data)

4

使用Pongo,它是Go模板的超集,它支持{{extends}}和{{block}}标签以进行模板继承,就像Django一样。


4

我已经几天都回过头来回答这个问题,终于忍无可忍,为此写了一个小的抽象层/预处理器。它基本上是:

  • 将'extends'关键字添加到模板。
  • 允许覆盖“定义”调用(因此可以使用greggory的默认值)
  • 允许未定义的“模板”调用,它们只给出一个空字符串
  • 设置的默认值。在对的“模板”调用中。父母的

https://github.com/daemonl/go_sweetpl

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.