访问golang模板中引用对象的属性(Google app engine)

时间:2016-04-03 11:18:35

标签: google-app-engine templates go data-modeling google-cloud-datastore

我有一个数据模型Sections:

type Sections struct{
    SectionName     string
    IsFather        bool
    ParentSection   *datastore.Key
}

我将部分作为值传递给golang模板,我希望得到ParentSection名称ParentSection.SectionName,那么如何从python jinja2中的{{ParentSection.get().SectionName}}等模板执行此操作?< / p>

1 个答案:

答案 0 :(得分:0)

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来加载数据存储区中的实体,因此您必须在模板参数中使其可用。所以你的模板参数可能如下所示:

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)

现在假设您有一个名为Sections的父"parSecName",您的孩子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

如果您不想在实体的密钥本身中“存储”父密钥,也可以只存储密钥的名称或密钥的ID(取决于您使用的内容),因为密钥可以构建。