英文:
Cannot bind mysql data to html template in golang
问题
更新:无论从任何地方来看,都没有错误!在浏览器中,控制台或网络选项卡中没有错误。在运行Go代码的终端中,也没有错误。所有Go中的错误都已记录;为了简洁起见,我在问题中删除了错误处理。
我试图按照一本关于使用Go编写Web应用程序的书进行操作。我有一个本地的MySQL数据库,可以使用database/sql包从中获取数据。我正在使用html/template包解析模板,但是无论如何都无法将数据绑定到模板中。
这是模型:
type Snippet struct {
    ID      int
    Title   string
    Content string
    Created time.Time
    Expires time.Time
}
这是用于显示数据的handler(省略了错误处理):
func (app *application) showSnippet(w http.ResponseWriter, r *http.Request) {
    id, _ := strconv.Atoi(r.URL.Query().Get("id"))
    s, _ := app.snippets.Get(id) // 从数据库获取数据!
    files := []string{
        "./ui/html/show.page.tmpl", // 这是模板。
        "./ui/html/base.layout.tmpl",
        "./ui/html/footer.partial.tmpl", // 可以是相对路径或绝对路径!
    }
    ts, _ := template.ParseFiles(files...)
    _ = ts.Execute(w, s) // 将模板集内容作为响应正文写入;
    // 注意:这确实打印出数据,所以数据确实从数据库中检索到。
    fmt.Fprintf(w, "%s\n%s", s.Title, s.Content)
}
这是show.page.tmpl模板:
{{template "base" .}}
{{define "title"}}Snippet #{{.ID}}{{end}}
{{define "main"}}
<div class='snippet'>
    <div class='metadata'>
        <strong>{{.Title}}</strong>
        <span>#{{.ID}}</span>
    </div>
    <pre><code>{{.Content}}</code></pre>
    <div class='metadata'>
        <time>Created: {{.Created}}</time>
        <time>Expires: {{.Expires}}</time>
    </div>
</div>
{{end}}
在页面上,它不显示数据,因为数据为空;但是底部的调试行打印得很好。
出了什么问题?
英文:
UPDATE: There is no error from anywhere whatsoever! In the browser, there is no error in the console or network tab. In the terminal running the go code, there is no error either. All errors in go are logged; for brevity I removed the error handling in the question.
Trying to follow a book about writing web app using Go.
I have a local mysql db which I can get data from using database/sql package. I am parsing the template using html/template package but somehow can't bind the data into the template.
This is the model:
type Snippet struct {
	ID      int
	Title   string
	Content string
	Created time.Time
	Expires time.Time
}
This is the handler for showing the data (error handling is omitted):
func (app *application) showSnippet(w http.ResponseWriter, r *http.Request) {
	id, _ := strconv.Atoi(r.URL.Query().Get("id"))
	s, _ := app.snippets.Get(id) // get data from database!
	files := []string{
		"./ui/html/show.page.tmpl", // this is the template.
		"./ui/html/base.layout.tmpl",
		"./ui/html/footer.partial.tmpl", // either relative or absolute path!
	}
	ts, _ := template.ParseFiles(files...)
	_ = ts.Execute(w, s) // write the template set content as the response body; 
	
	// NOTE: this does print out data fine so data is indeed retrieved from the db.
	fmt.Fprintf(w, "%s\n%s", s.Title, s.Content) 
}
Here is the show.page.tmpl template:
{{template "base" .}}
{{define "title"}}Snippet #{{.ID}}{{end}}
{{define "main"}}
<div class='snippet'>
    <div class='metadata'>
        <strong>{{.Title}}</strong>
        <span>#{{.ID}}</span>
    </div>
    <pre><code>{{.Content}}</code></pre>
    <div class='metadata'>
        <time>Created: {{.Created}}</time>
        <time>Expires: {{.Expires}}</time>
    </div>
</div>
{{end}}
On the page, it doesn't display the data as it's empty; but the debug line is printed fine at the bottom.
What went wrong?
答案1
得分: 1
在HTTP处理程序中编译模板不是一个好主意(基本上在每个请求中)。
假设你使用模板名称和.htm扩展名创建了文件,你可以像这样做(甚至将它们添加到应用程序结构中):
// 定义一个全局的 templates 变量(或者将其添加到应用程序中,如果你想的话)
var templates *template.Template
// 编译模板
// 在名为 "templates" 的子目录中,文件以 .htm 结尾
func getTemplates() (templates *template.Template, err error) {
    var allFiles []string
    templateDir := "templates"
    files2, _ := ioutil.ReadDir(templateDir)
    for _, file := range files2 {
        filename := file.Name()
        if strings.HasSuffix(filename, ".htm") {
            filePath := filepath.Join(templateDir, filename)
            allFiles = append(allFiles, filePath)
        }
    }
    templates, err = template.New("").ParseFiles(allFiles...)
    LogPanic(err, "Error building templates")
    return
}
// 在初始化时加载模板
func init() {
    var err error
    templates, err = getTemplates()
    if err != nil {
        log.Panicf("%s: %s \n", "ERROR compiling templates", err)
    }
}
现在你已经编译了模板,可以在HTTP处理程序中执行它们,并在有错误时记录错误(如果你看到任何错误,请像 Cerise Limón 建议的那样分享)记得在代码中更新模板名称。
func (app *application) showSnippet(w http.ResponseWriter, r *http.Request) {
    id, _ := strconv.Atoi(r.URL.Query().Get("id"))
    s, _ := app.snippets.Get(id)
    err := templates.ExecuteTemplate(w, "template_name", s)
    if err != nil {
        log.Printf("%s: %s \n", "ERROR executing template", err)
    }
    fmt.Fprintf(w, "%s\n%s", s.Title, s.Content)
}
英文:
It's not a good idea to compile the templates in the HTTP handler (basically in every request)
Assuming you created the files with the template names and an .htm extension, you can do something like this (or even add them to the application struct)
// Define a global templates variable (or add it to the application if you want)
var templates *template.Template
// For compiling the templates
// in a subdirectory called "templates" with files ending in .htm
func getTemplates() (templates *template.Template, err error) {
var allFiles []string
templateDir := "templates"
files2, _ := ioutil.ReadDir(templateDir)
for _, file := range files2 {
filename := file.Name()
if strings.HasSuffix(filename, ".htm") {
filePath := filepath.Join(templateDir, filename)
allFiles = append(allFiles, filePath)
}
}
templates, err = template.New("").ParseFiles(allFiles...)
LogPanic(err, "Error building templates")
return
}
// load them on init
func init() {
var err error
templates, err = getTemplates()
if err != nil {
log.Panicf("%s: %s \n", "ERROR compiling templates", err)
}
}
Now that you have the templates compiled, you can execute them in the HTTP handler, and log the error if there's any (please share if you see any errors as Cerise Limón suggested) remember to update the template name in the code.
func (app *application) showSnippet(w http.ResponseWriter, r *http.Request) {
id, _ := strconv.Atoi(r.URL.Query().Get("id"))
s, _ := app.snippets.Get(id)
err := templates.ExecuteTemplate(w, "template_name", s)
if err != nil {
log.Printf("%s: %s \n", "ERROR executing template", err)
}
fmt.Fprintf(w, "%s\n%s", s.Title, s.Content) 
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。



评论