我有一个数据模型Sections:
type Sections struct{
SectionName string
IsFather bool
ParentSection *datastore.Key
}
我将部分作为值传递给 golang 模板,我想获取 ParentSection
名称 ParentSection.SectionName
那么我如何从 jinja2之类的模板中执行此操作
在 python {{ParentSection.get().SectionName}}
?
最佳答案
html/template
包不是“appengine-aware”,它不知道 GAE 平台,也不支持自动解析此类引用。
根据设计理念,模板不应包含复杂的逻辑。如果某些东西(或看起来)在模板中过于复杂,则应该在函数中实现。您可以使用 Template.Funcs()
注册您的自定义函数您可以从模板中调用的方法。
对于您的用例,我推荐以下自定义函数,它通过键加载 Sections
:
func loadSections(ctx appengine.Context, k *datastore.Key) (*Sections, error) {
s := Sections{}
err := datastore.Get(ctx, k, &s)
return &s, err
}
请注意,您需要 Context
来从 Datastore 加载实体,因此您也必须在模板参数中使其可用。所以你的模板参数可能看起来像这样:
ctx := appengine.NewContext(r)
m := map[string]interface{}{
"Sections": s, // A previously loaded Sections
"Ctx": ctx,
}
并且通过注册和使用这个功能,你可以得到你想要的:
t := template.Must(template.New("").Funcs(template.FuncMap{
"loadSections": loadSections,
}).Parse(`my section name: {{.Sections.SectionName}},
parent section name: {{(loadSections .Ctx .Sections.ParentSection).SectionName}}`))
t.Execute(w, m)
现在假设您有一个名为 "parSecName"
的父 Sections
,并且您有一个名为 的子
,并且 child 的 Sections
>“childSecName”ParentSection
指向父的 Sections
。执行上面的模板你会看到这个结果:
my section name: childSecName,
parent section name: parSecName
完整示例
请参阅此完整的工作示例。注意:它仅用于演示目的,并未针对生产进行优化。
它注册了/put
路径来插入2个Sections
。您可以使用任何其他路径来执行模板。所以像这样测试它:
首先插入 2 个 Sections
:
http://localhost:8080/put
然后执行并查看模板结果:
http://localhost:8080/view
完整的可运行代码:
// +build appengine
package gplay
import (
"appengine"
"appengine/datastore"
"html/template"
"net/http"
)
func init() {
http.HandleFunc("/put", puthandler)
http.HandleFunc("/", myhandler)
}
func myhandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
s := Sections{}
if err := datastore.Get(ctx, datastore.NewKey(ctx, "Sections", "", 2, nil), &s); err != nil {
panic(err)
}
m := map[string]interface{}{
"Sections": s,
"Ctx": ctx,
}
t := template.Must(template.New("").Funcs(template.FuncMap{
"loadSections": loadSections,
}).Parse(`my section name: {{.Sections.SectionName}},
parent section name: {{(loadSections .Ctx .Sections.ParentSection).SectionName}}`))
t.Execute(w, m)
}
func loadSections(ctx appengine.Context, k *datastore.Key) (*Sections, error) {
s := Sections{}
err := datastore.Get(ctx, k, &s)
return &s, err
}
func puthandler(w http.ResponseWriter, r *http.Request) {
ctx := appengine.NewContext(r)
s := Sections{"parSecName", false, nil}
var k *datastore.Key
var err error
if k, err = datastore.Put(ctx, datastore.NewKey(ctx, "Sections", "", 1, nil), &s); err != nil {
panic(err)
}
s.SectionName = "childSecName"
s.ParentSection = k
if _, err = datastore.Put(ctx, datastore.NewKey(ctx, "Sections", "", 2, nil), &s); err != nil {
panic(err)
}
}
type Sections struct {
SectionName string
IsFather bool
ParentSection *datastore.Key
}
一些笔记
这种子-父关系可以用 Key
本身建模,因为一个键可以选择包含一个父 Key
。
如果您不想将父 key “存储”在实体的 key 本身中,那么只存储 key 的名称或 key 的 ID(取决于您使用的是什么)也可能就足够了,从那以后可以构造 key 。
关于google-app-engine - 访问 golang 模板中引用对象的属性(Google 应用引擎),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36384759/