Go pongo2
最后修改时间 2024 年 4 月 11 日
在本文中,我们将展示如何在 Golang 中使用 pongo2 模板引擎处理模板。
模板引擎是一种旨在将模板与数据结合以生成文档的库。模板引擎用于生成大量电子邮件、在源代码预处理中,或用于生成动态 HTML 页面。
模板由静态数据和动态区域组成。动态区域随后会被数据替换。渲染函数随后会将模板与数据结合起来。模板引擎用于将模板与数据模型结合以生成文档。
pongo2 库是一个受 Django 模板引擎启发的 Go 模板引擎。
pongo2 在模板字符串中使用各种分隔符
{% %}
- 语句{{ }}
- 要打印到模板输出的表达式{# #}
- 不包含在模板输出中的注释# ##
- 行语句
模板可以从字符串(使用 pongo2.FromString
)、文件(使用 pongo2.FromFile
)或字节(使用 pongo2.FromBytes
)读取。
文档使用 Execute
、ExecuteWriter
或 ExecuteBytes
函数进行渲染。这些函数接受一个 Context
,它向模板提供常量、变量、实例或函数。
Go pongo2.FromString
pongo2.FromString
从字符串读取模板。
package main import ( "fmt" "log" "github.com/flosch/pongo2/v5" ) func main() { tpl, err := pongo2.FromString("Hello {{ name }}!") if err != nil { log.Fatal(err) } res, err := tpl.Execute(pongo2.Context{"name": "John Doe"}) if err != nil { log.Fatal(err) } fmt.Println(res) }
该示例生成一个简单的文本消息。
tpl, err := pongo2.FromString("Hello {{ name }}!")
要打印的变量放在 {{ }}
括号内。
res, err := tpl.Execute(pongo2.Context{"name": "John Doe"})
我们使用 Execute
渲染最终字符串。在上下文中,我们为 name
变量传递了一个值。
$ go run main.go Hello John Doe!
package main import ( "fmt" "log" "github.com/flosch/pongo2/v5" ) func main() { tpl, err := pongo2.FromString("{{ name }} is a {{ occupation }}") if err != nil { log.Fatal(err) } name, occupation := "John Doe", "gardener" ctx := pongo2.Context{"name": name, "occupation": occupation} res, err := tpl.Execute(ctx) if err != nil { log.Fatal(err) } fmt.Println(res) }
在此示例中,我们在上下文中传递了两个变量。
$ go run main.go John Doe is a gardener
Go pongo2.FromFile
使用 pongo2.FromFile
函数,我们从文件读取模板。
{{ name }} is a {{ occupation }}
这是模板文件。
package main import ( "fmt" "log" "github.com/flosch/pongo2/v5" ) func main() { tpl, err := pongo2.FromFile("message.tpl") if err != nil { log.Fatal(err) } name, occupation := "John Doe", "gardener" ctx := pongo2.Context{"name": name, "occupation": occupation} res, err := tpl.Execute(ctx) if err != nil { log.Fatal(err) } fmt.Println(res) }
该示例生成一个简单的消息,同时从文件读取模板。
Go pongo2 for 指令
for
指令用于在模板中迭代数据集合。
{% for word in words -%} {{ word }} {% endfor %}
在模板中,我们使用 for
指令遍历 words
数据结构的元素。`-` 字符会去除空白字符。
package main import ( "fmt" "log" "github.com/flosch/pongo2/v5" ) func main() { tpl, err := pongo2.FromFile("words.tpl") if err != nil { log.Fatal(err) } words := []string{"sky", "blue", "storm", "nice", "barrack", "stone"} ctx := pongo2.Context{"words": words} res, err := tpl.Execute(ctx) if err != nil { log.Fatal(err) } fmt.Println(res) }
在程序中,我们将单词切片传递给模板引擎。我们得到一个单词列表作为输出。
$ go run main.go sky blue storm nice barrack stone
Go pongo2 filter
可以对数据应用过滤器来修改它们。过滤器在 `|` 字符后应用。
{% for word in words -%} {{ word }} has {{ word | length }} characters {% endfor %}
length
过滤器返回字符串的大小。
package main import ( "fmt" "log" "github.com/flosch/pongo2/v5" ) func main() { tpl, err := pongo2.FromFile("words.tpl") if err != nil { log.Fatal(err) } words := []string{"sky", "blue", "storm", "nice", "barrack", "stone"} ctx := pongo2.Context{"words": words} res, err := tpl.Execute(ctx) if err != nil { log.Fatal(err) } fmt.Println(res) }
在程序中,我们将单词切片传递给模板。我们打印每个单词及其大小。
$ go run main.go sky has 3 characters blue has 4 characters storm has 5 characters nice has 4 characters barrack has 7 characters stone has 5 characters
Go pongo2 if 条件
可以使用 if/endif
指令创建条件。
{% for todo in todos -%} {% if todo.Done %} {{- todo.Title -}} {% endif %} {% endfor %}
在模板文件中,我们使用 if 指令仅输出已完成的任务。
package main import ( "fmt" "log" "github.com/flosch/pongo2/v5" ) type Todo struct { Title string Done bool } type Data struct { Todos []Todo } func main() { tpl, err := pongo2.FromFile("todos.tpl") if err != nil { log.Fatal(err) } todos := []Todo{ {Title: "Task 1", Done: false}, {Title: "Task 2", Done: true}, {Title: "Task 3", Done: true}, {Title: "Task 4", Done: false}, {Title: "Task 5", Done: true}, } ctx := pongo2.Context{"todos": todos} res, err := tpl.Execute(ctx) if err != nil { log.Fatal(err) } fmt.Println(res) }
我们从待办事项切片生成输出。在输出中,我们只包含已完成的任务。
服务器示例
在下一个示例中,我们在服务器应用程序中使用模板。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Users</title> </head> <body> <table> <thead> <tr> <th>Name</th> <th>Occupation</th> </tr> </thead> <tbody> {% for user in users %} <tr> <td>{{ user.Name }} </td> <td>{{ user.Occupation }}</td> </tr> {% endfor %} </tbody> </table> </body> </html>
输出是一个 HTML 文件。用户显示在 HTML 表格中。
package main import ( "net/http" "github.com/flosch/pongo2/v5" ) type User struct { Name string Occupation string } var tpl = pongo2.Must(pongo2.FromFile("users.html")) func usersHandler(w http.ResponseWriter, r *http.Request) { users := []User{ {Name: "John Doe", Occupation: "gardener"}, {Name: "Roger Roe", Occupation: "driver"}, {Name: "Peter Smith", Occupation: "teacher"}, } err := tpl.ExecuteWriter(pongo2.Context{"users": users}, w) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } } func main() { http.HandleFunc("/users", usersHandler) http.ListenAndServe(":8080", nil) }
Web 服务器为 /users
URL 路径返回一个带有用户表的 HTML 页面。
var tpl = pongo2.Must(pongo2.FromFile("index.html"))
pongo2.Must
是一个辅助函数,它在应用程序启动时预编译模板。
err := tpl.ExecuteWriter(pongo2.Context{"users": users}, w)
ExecuteWriter
使用给定的上下文渲染模板,并在成功时将输出写入响应写入器。出错时不写入任何内容;而是返回错误。
来源
在本文中,我们使用第三方 pongo2 模板引擎创建了动态文档。