How to pass multiple data to Go template?

huangapple go评论82阅读模式
英文:

How to pass multiple data to Go template?

问题

我想将两个数据对象传递给Go模板。一个是MongoDB查询结果,另一个是整数数组。

MongoDB查询代码如下:

var results []User
sess, db := GetDatabase()
defer sess.Close()
c := db.C("user")
err := c.Find(nil).All(&results)

我想通过以下代码传递'results'和一个整数数组:

GetTemplate("list").Execute(w, ???????)

如果只有数据库查询结果,我们可以这样使用:

GetTemplate("list").Execute(w, results)

在模板中,我们可以通过{{.Name}}等方式访问它(其中Name是[]User的结构字段)。

请告诉我如何传递这些数据,并在模板中如何访问它们。

英文:

I want to pass two data objects to Go Template. One is a MongoDB query result and other is an integer array.

MongoDB Query:-

var results []User
sess, db := GetDatabase()
defer sess.Close()
c := db.C("user")
err := c.Find(nil).All(&results)

I want to sent 'result' and an int array through following code

GetTemplate("list").Execute(w,???????)

If there is only db result, we could use it as

GetTemplate("list").Execute(w,results)

and in template we could access it {{.Name}} etc. (where Name is a struct field of []User)

Please tell me how to pass these data and how to access them in template.

答案1

得分: 26

您只能传递一个值,但该值可以是多个值的组合,例如结构体、映射或切片。因此,只需将模板中的多个数据包装在structmap中。

使用struct的示例:

type Data struct {
    Results []User // 必须是导出的!
    Other   []int  // 必须是导出的!
}

data := &Data{results, []int{1, 2, 3}}
if err := GetTemplate("list").Execute(w, data); err != nil {
    // 处理错误
}

还要注意,不需要新的命名类型,您也可以使用匿名结构体字面量,如下所示:

data := struct {
    Results []User // 必须是导出的!
    Other   []int  // 必须是导出的!
}{results, []int{1, 2, 3}}

使用map的示例:

m := map[string]interface{}{
    "Results": results,
    "Other":   []int{1, 2, 3},
}

if err := GetTemplate("list").Execute(w, m); err != nil {
    // 处理错误
}

请注意,使用映射时,不需要使用大写的字符串作为键,例如您也可以使用"results""other"(但我认为最好使用以大写字母开头的键,这样如果将来转换为struct,您需要进行的更正就会更少)。

在这两种情况下,您可以使用{{.Results}}引用[]User结果,使用{{.Other}}引用附加的整数切片。

因此,例如要遍历用户:

{{range .Results}}
    用户名:{{.Name}}
{{end}}

使用slice的示例:

s := []interface{}{
    results,
    []int{1, 2, 3},
}

if err := GetTemplate("list").Execute(w, s); err != nil {
    // 处理错误
}

这种方法不太易读,但是是可行的解决方案。在模板中,您必须对模板数据进行索引以获取“单个”值,例如:

{{range index . 0}}
    用户名:{{.Name}}
{{end}}

其他:{{index . 1}}

Go Playground上尝试一下。

其他方法...

还有其他“理论上”的方法,但我不会使用它们仅仅因为它们能工作。

例如,您还可以传递一个通道,从中接收值。

另一种解决方案可能是注册自定义函数,当调用时会返回这些值。

英文:

You may only pass a single value, but that value may be a composed value of multiple values, e.g. a struct, map or slice. So simply wrap your multiple data intended for the template in a struct or in a map.

Example with a struct:

type Data struct {
    Results []User // Must be exported!
    Other   []int  // Must be exported!
}

data := &Data{results, []int{1, 2, 3}}
if err := GetTemplate("list").Execute(w, data); err != nil {
    // Handle error
}

Also note that a new, named type is not required, you could also use an anonymous struct literal, which could look like this:

data := struct {
    Results []User // Must be exported!
    Other   []int  // Must be exported!
}{results, []int{1, 2, 3}}

Example with a map:

m := map[string]interface{}{
    "Results": results,
    "Other":   []int{1, 2, 3},
}

if err := GetTemplate("list").Execute(w, m); err != nil {
    // Handle error
}

Note that using a map, it is not required to use capitalized strings as keys, e.g. you could've used "results" and "other" too (but in my opinion it's better to use keys with capital starting letters, should you move to struct sometimes in the future, you would have less corrections to make).

In both cases you may refer to the []User results with {{.Results}} and to the additional int slice with {{.Other}}.

So for example to range over the users:

{{range .Results}}
    User name:{{.Name}}
{{end}}

Example with a slice:

s := []interface{}{
    results,
    []int{1, 2, 3},
}

if err := GetTemplate("list").Execute(w, s); err != nil {
    // Handle error
}

This is less readable, but a viable solution. In the template you have to index the template data to get the "individual" values, e.g.:

{{range index . 0}}
    User name:{{.Name}}
{{end}}

Other: {{index . 1}}

Try it on the Go Playground.

Other ways...

There are other "theoretical" ways too, but I wouldn't use them just because it works.

For example, you could also pass in a channel from which receives would provide the values.

Yet another solution could be to register custom functions which when called would return the values.

答案2

得分: 1

你应该定义一个包含数据库查询结果的结构体,然后将该结构体赋值给Execute方法。

tmpl.Execute需要一个Writer接口和一个struct

type Inventory struct {
    Material string
    Count    uint
}

items := Inventory{"裤子", 1}
if err := GetTemplate("list").Execute(w, items); err != nil {
    // ... 做你的工作
}
英文:

You should define a struct populated with the database results query, then assign that struct to the Execute method.

tmpl.Execute require a Writer interface and a struct

type Inventory struct {
	Material string
	Count    uint
}

items := Inventory{"trouser", 1}    
if err := GetTemplate("list").Execute(w, items); err != nil {
    // ... do your work
}

答案3

得分: 0

你可以使用range关键字将结构体放在另一个结构体中。例如:

type Data struct {
    Users      []User
    Developers []Developer
}

var data = Data{
    Users:      ...,
    Developers: ...,
}

err := t.Execute(w, &data)
if err != nil {
    panic(err)
}

{{range .Users}}{{.UserName}}
{{end}}
{{range .Developers}}{{.DeveloperName}}
{{end}}

请注意,这是一个示例代码片段,其中UserDeveloper是自定义的结构体类型。你需要根据实际情况进行适当的替换。

英文:

You can put your structs inside another struct using the range keyword. e.g

type Data struct {
    Users  []User
    Developers []Developer
}


var data = Data{
    Users:  ...,
    Developers: ...,
}

err := t.Execute(w, &data)
if err != nil {
    panic(err)
}

{{range .Users}}{{.UserName}}
{{end}}
{{range .Developers}}{{.DeveloperName}}
{{end}}

huangapple
  • 本文由 发表于 2016年2月5日 20:18:03
  • 转载请务必保留本文链接:https://go.coder-hub.com/35224066.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定