模板继承加载了空页面

huangapple go评论91阅读模式
英文:

Template inheritance loads empty page

问题

我正在使用Golang+AppEngine开发一个基本应用程序,并尝试实现像Django那样的模板继承。到目前为止,我有以下代码:

var TmplBasePath = "templates/"

var BasePageTmplPath = []string{TmplBasePath + "base.html"}

type Page struct {
    Title string
    Ctx   appengine.Context
}

func NewPage(r *http.Request, title string) *Page {
    return &Page{Title: title}
}

func (p *Page) Display(w http.ResponseWriter, tmplPath string) {
    tmplPath = TmplBasePath + tmplPath
    tmpl := template.New("PAGE")
    tmpl = template.Must(template.ParseFiles(BasePageTmplPath...))
    tmpl = template.Must(template.ParseFiles(tmplPath))
    if err := tmpl.Execute(w, nil); err != nil {
        p.Ctx.Errorf("%v ", err)
    }
}

func init() {
    http.HandleFunc("/", home)
}

func home(w http.ResponseWriter, r *http.Request) {
    p := NewPage(r, "home")
    p.Display(w, "index.html")

}

我的模板如下:

base.html

{{ define "PAGE" }}

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
        <title> Expat Duka </title>
    <link rel="stylesheet" href="css/bootstrap.min.css"/>
</head>
<body>

    <nav class="navbar navbar-inverse navbar-fixed-top">
      <div class="container">
        <div class="navbar-header">
          <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
            <span class="sr-only">Toggle navigation</span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
            <span class="icon-bar"></span>
          </button>
          <a class="navbar-brand" href="#">Project name</a>
        </div>
        <div id="navbar" class="collapse navbar-collapse">
          <ul class="nav navbar-nav">
            <li class="active"><a href="#">Home</a></li>
            <li><a href="#about">About</a></li>
            <li><a href="#contact">Contact</a></li>
          </ul>
        </div><!--/.nav-collapse -->
      </div>
    </nav>

     <div class="container">

      <div class="starter-template">
        {{template "CONTENT" .}}
       
      </div>

    </div><!-- /.container -->

</body>
</html>
{{end}}

index.html

{{define "CONTENT"}}
        <h1> Welcome to Expat Duka </h1>
       
{{end}}

页面加载时没有错误,但是页面是空白的。你知道我做错了什么吗?

英文:

I'm working on a basic app in Golang+AppEngine and I'm trying to implement template inheritance like Django, so far I have this code:

var TmplBasePath = &quot;templates/&quot;
var BasePageTmplPath = []string{TmplBasePath + &quot;base.html&quot;}
type Page struct {
Title string
Ctx   appengine.Context
}
func NewPage(r *http.Request, title string) *Page {
return &amp;Page{Title: title}
}
func (p *Page) Display(w http.ResponseWriter, tmplPath string) {
tmplPath = TmplBasePath + tmplPath
tmpl := template.New(&quot;PAGE&quot;)
tmpl = template.Must(template.ParseFiles(BasePageTmplPath...))
tmpl = template.Must(template.ParseFiles(tmplPath))
if err := tmpl.Execute(w, nil); err != nil {
p.Ctx.Errorf(&quot;%v &quot;, err)
}
}
func init() {
http.HandleFunc(&quot;/&quot;, home)
}
func home(w http.ResponseWriter, r *http.Request) {
p := NewPage(r, &quot;home&quot;)
p.Display(w, &quot;index.html&quot;)
}

My templates:
base.html

{{ define &quot;PAGE&quot;}}
&lt;!DOCTYPE html&gt;
&lt;html lang=&quot;en&quot;&gt;
&lt;head&gt;
&lt;meta charset=&quot;utf-8&quot;&gt;
&lt;meta http-equiv=&quot;X-UA-Compatible&quot; content=&quot;IE=edge&quot;&gt;
&lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot;&gt;
&lt;title&gt; Expat Duka &lt;/title&gt;
&lt;link rel=&quot;stylesheet&quot; href=&quot;css/bootstrap.min.css&quot;/&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;nav class=&quot;navbar navbar-inverse navbar-fixed-top&quot;&gt;
&lt;div class=&quot;container&quot;&gt;
&lt;div class=&quot;navbar-header&quot;&gt;
&lt;button type=&quot;button&quot; class=&quot;navbar-toggle collapsed&quot; data-toggle=&quot;collapse&quot; data-target=&quot;#navbar&quot; aria-expanded=&quot;false&quot; aria-controls=&quot;navbar&quot;&gt;
&lt;span class=&quot;sr-only&quot;&gt;Toggle navigation&lt;/span&gt;
&lt;span class=&quot;icon-bar&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;icon-bar&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;icon-bar&quot;&gt;&lt;/span&gt;
&lt;/button&gt;
&lt;a class=&quot;navbar-brand&quot; href=&quot;#&quot;&gt;Project name&lt;/a&gt;
&lt;/div&gt;
&lt;div id=&quot;navbar&quot; class=&quot;collapse navbar-collapse&quot;&gt;
&lt;ul class=&quot;nav navbar-nav&quot;&gt;
&lt;li class=&quot;active&quot;&gt;&lt;a href=&quot;#&quot;&gt;Home&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#about&quot;&gt;About&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#contact&quot;&gt;Contact&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;&lt;!--/.nav-collapse --&gt;
&lt;/div&gt;
&lt;/nav&gt;
&lt;div class=&quot;container&quot;&gt;
&lt;div class=&quot;starter-template&quot;&gt;
{{template &quot;CONTENT&quot; .}}
&lt;/div&gt;
&lt;/div&gt;&lt;!-- /.container --&gt;
&lt;/body&gt;
&lt;/html&gt;
{{end}}

index.html

{{define &quot;CONTENT&quot;}}
&lt;h1&gt; Welcome to Expat Duka &lt;/h1&gt;
{{end}}

The page loads, no errors, but its blank, any idea what I'm doing wrong

答案1

得分: 4

首先,这是你的问题:

tmpl := template.New("PAGE")
tmpl = template.Must(template.ParseFiles(BasePageTmplPath...))
tmpl = template.Must(template.ParseFiles(tmplPath))

template.ParseFiles() 返回一个新的模板(Must() 只是检查参数并返回相同的模板)。所以当你在第一行创建一个新的模板(使用 template.New()),你失去了它,因为在第二行你用 ParseFiles() 创建了另一个模板并将其赋值给相同的 tmpl 变量。然后在第三行,你又创建了一个新的、完全独立的第三个模板,并将其赋值给 tmpl 变量。

这三个模板是完全独立的,它们互相不知道!

如果你希望这些模板相互了解(以便可以引用/包含彼此),可以使用 Template.Parse()Template.ParseFiles() 方法,就像这个例子一样:

tmpl := template.New("PAGE")
template.Must(tmpl.ParseFiles(BasePageTmplPath...))
template.Must(tmpl.ParseFiles(tmplPath))

现在,你在 tmpl 变量中有多个关联的模板,执行你感兴趣的那个:

if err := tmpl.ExecuteTemplate(w, "index.html", nil); err != nil {
    p.Ctx.Errorf("%v ", err)
}

注意:

在处理请求的处理程序中解析模板是非常不好的做法,它需要相对较长的时间。而且每次提供请求时解析和创建模板会在内存中生成大量的值,然后被丢弃(因为它们不会被重用),给垃圾回收器增加额外的工作量。

在应用程序启动时解析模板,将其存储在一个变量中,只有在请求到达时才需要执行模板。有关更多详细信息,请参见这个答案

英文:

Beforehand: Please note that there is a template.ParseFiles() function and there is a Template.ParseFiles() method. The first one returns a new template, the second you have to call on an already created template and it returns an associated template. Associated templates know about each other, so you don't even have to store the returned new template if you already stored the one whose method you called.


Firstly this is your problem:

tmpl := template.New(&quot;PAGE&quot;)
tmpl = template.Must(template.ParseFiles(BasePageTmplPath...))
tmpl = template.Must(template.ParseFiles(tmplPath))

template.ParseFiles() returns a new template (Must() just checks its parameters and returns the same). So when you create a new in the first line (with template.New()), you lose it because in the 2nd line you create another one with ParseFiles() and assign it to the same tmpl variable.
And yet again you create a new, completely independent 3rd template in the 3rd line and you assign that to the tmpl variable.

These 3 templates are completely independent and they don't know about each other!

If you want the templates to know about each other (and so they can refer/include each other), use the Template.Parse() or Template.ParseFiles() methods as in this example:

tmpl := template.New(&quot;PAGE&quot;)
template.Must(tmpl.ParseFiles(BasePageTmplPath...))
template.Must(tmpl.ParseFiles(tmplPath))

And now you have multiple associated templates in the tmpl variable, execute the one you're interested in:

if err := tmpl.ExecuteTemplate(w, &quot;index.html&quot;, nil); err != nil {
p.Ctx.Errorf(&quot;%v &quot;, err)
}

Notes:

Also it is very bad practice to parse templates in the handler which serves the request, it takes relatively long time. Also parsing and creating the template each time when serving a request generates lots of values in memory which are then thrown away (because they are not reused) giving additional work for the garbage collector.

Parse the templates when your application starts, store it in a variable, and you only have to execute the template when a request comes in. See this answer for more details.

huangapple
  • 本文由 发表于 2015年3月12日 11:10:55
  • 转载请务必保留本文链接:https://go.coder-hub.com/29001256.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定