英文:
golang html/template templates with same names in different directories
问题
问题:
如果不同文件夹中的方法(具有不同路由)需要指定特定的模板,该如何操作?
描述:
我在数据库中有两个表,Users和Agency,它们具有不同的字段。对于每个表,我都使用SELECT函数创建了一个用于列出对象的路由。
路由器:
r := mux.NewRouter() // gorilla/mux
r.HandleFunc("/user", handlers.UserList).Methods("GET")
r.HandleFunc("/agency", handlers.AgencyList).Methods("GET")
其中handlers是一个带有数据库指针和模板的结构体,
type Handler struct {
DB *sql.DB
Tmpl *template.Template
}
它具有用于捕获响应的方法:
func (h *Handler) AgencyList(w http.ResponseWriter, r *http.Request) {
Agencys := []*Agency{}
rows, err := h.DB.Query(`SELECT Id, Name, IsActive FROM Agencys`)
// 将对象追加到Agencys中并处理错误的代码等
err = h.Tmpl.ExecuteTemplate(w, "index.html", struct{ Agencys []*Agency }{Agencys: Agencys})
// 其他代码和错误处理
}
处理Users列表函数的原则相同。
此处理程序还具有用于GET(一个对象)、POST和DELETE方法的方法,对于每个方法,我都需要特定的模板(用于编辑等)。
所以。
在这个例子中,我有一个名为templates的目录,其中有两个子目录"user"和"agency",每个"subject"(用户和机构)都有一个用于列出对象的index.html文件。
templates\
\agency
--\edit.html
--\index.html
... 用于agency的其他html文件
\user
--\edit.html
--\index.html
... 用于用户的其他html文件
... 用于其他数据库对象的其他目录
我使用了以下代码:
func main() {
handlers := &handler.Handler{
DB: db,
Tmpl: template.Must(template.ParseGlob("templates/*.html")), // 用于根模板
}
// 下面的代码是为了避免出现panic: read templates/agency: is a directory
template.Must(handlers.Tmpl.ParseGlob("templates/user/*.html"))
template.Must(handlers.Tmpl.ParseGlob("templates/agency/*.html"))
r := mux.NewRouter()
r.HandleFunc("/", handlers.Index).Methods("GET") // 根目录
r.HandleFunc("/user", handlers.UserList).Methods("GET")
r.HandleFunc("/agency", handlers.AgencyList).Methods("GET")
// 其他使用ListenAndServe()的代码
}
最后,我在模板中捕获了错误,例如:
template: index.html:26:12: executing "index.html" at <.Agencys>: can't evaluate field Agencys in type struct { Users []*handler.User }
当我尝试在浏览器中调用localhost/user进行列表时(因为它们是不同的“对象”,具有不同的字段,当然会出错)。看起来像是ParseGlob(agency/)在ParseGlob(user/)之后重新定义了相同名称的模板。
我尝试找到解决方案,例如:
err = h.Tmpl.ExecuteTemplate(w, "templates/user/index.html", post)
在UserList()方法中指定需要的模板。
也许这不是一个好的解决方案;也许,如果我在模板名称中使用前缀(例如在templates目录中使用listAgency.html和listUser.html)而不是为每个对象使用不同的目录,那可能会更好。我尝试过这种方式,但看起来不太美观。
英文:
Question:
How can I specify a specific template for a specific method (with different routes), if they are in different folders and named the same?
Descript:
I have two tables in Database, Users and Agency with different fields for example. For each of them I've made router for list objects by SELECT function.
Router:
r := mux.NewRouter() // gorilla/mux
r.HandleFunc("/user", handlers.UserList).Methods("GET")
r.HandleFunc("/agency", handlers.AgencyList).Methods("GET")
where handlers is a struct with database pointer and templates,
type Handler struct {
DB *sql.DB
Tmpl *template.Template
}
and it's have a methods for catching responses:
func (h *Handler) AgencyList(w http.ResponseWriter, r *http.Request) {
Agencys := []*Agency{}
rows, err := h.DB.Query(`SELECT Id, Name, IsActive FROM Agencys`)
// etc code for append objects into Agencys and error handling
err = h.Tmpl.ExecuteTemplate(w, "index.html", struct{ Agencys []*Agency }{Agencys: Agencys})
// etc code and error handling
}
Same principles in handling Users list function.
This handler have also methods for GET (one object) POST and DELETE methods, and for each of them I need specific template for working (for editing etc).
So.
In this example I have directory templates, where I have two sub-directories "user" and "agency" with files index.html (for listing objects) for each "subject" (user and agency).
templates\
\agency
--\edit.html
--\index.html
... etc htmls for agency
\user
--\edit.html
--\index.html
... etc htmls for users
... etc dirs for other DB-objects
And I'm using this:
func main() {
handlers := &handler.Handler{
DB: db,
Tmpl: template.Must(template.ParseGlob("templates/*.html")), // for root templates
}
// next code is avoid panic: read templates/agency: is a directory
template.Must(handlers.Tmpl.ParseGlob("templates/user/*.html"))
template.Must(handlers.Tmpl.ParseGlob("templates/agency/*.html"))
r := mux.NewRouter()
r.HandleFunc("/", handlers.Index).Methods("GET") // root
r.HandleFunc("/user", handlers.UserList).Methods("GET")
r.HandleFunc("/agency", handlers.AgencyList).Methods("GET")
// etc code with ListenAndServe()
}
After all I catched error in template like
template: index.html:26:12: executing "index.html" at <.Agencys>: can't evaluate field Agencys in type struct { Users []*handler.User }
when I trying call localhost/user listing in browser (because it's different 'objects' with different fields, of course). Looks like ParseGlob(agency/) redefine tepmlates with same names after ParseGlob(user/)
I'm trying find solution like this:
err = h.Tmpl.ExecuteTemplate(w, "templates/user/index.html", post)
in method UserList() for pointing which template needs.
Maybe that's all is not good solution; maybe will be good, if I shall use prefixes in template's names (like listAgency.html and listUser.html in templates dir) instead of different directories for each object like now. I tried this way, but that looks not so pretty and beauty.
答案1
得分: 1
你可以像这样包装每个文件的内容,并给它起一个你想要的名字。
例如,打开文件 templates\user\index.html
,在顶部添加以下行:
{{ define "templates/user/index.html" }}
在底部添加以下行:
{{ end }}
然后,下面的代码就可以正常工作了:
err = h.Tmpl.ExecuteTemplate(w, "templates/user/index.html", post)
英文:
> I'm trying find solution like this:
> go
> err = h.Tmpl.ExecuteTemplate(w, "templates/user/index.html", post)
>
You can wrap each file's contents in a "define action" and name it what you want.
For example, open the file templates\user\index.html
and add a this line at the top
{{ define "templates/user/index.html" }}
and this line at the bottom
{{ end }}
and then the following
err = h.Tmpl.ExecuteTemplate(w, "templates/user/index.html", post)
will work.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论