英文:
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)
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论