pongo2 is the successor of pongo, a Django-syntax like templating-language.
Install/update using go get
(no dependencies required by pongo2):
go get -u github.com/flosch/pongo2
Please use the issue tracker if you're encountering any problems with pongo2 or if you need help with implementing tags or filters (create a ticket!). If possible, please use playground to create a short test case on what's wrong and include the link to the snippet in your issue.
New: Try pongo2 out in the pongo2 playground.
<html><head><title>Our admins and users</title></head>
{# This is a short example to give you a quick overview of pongo2's syntax. #}
{% macro user_details(user, is_admin=false) %}
<div class="user_item">
<!-- Let's indicate a user's good karma -->
<h2 {% if (user.karma >= 40) || (user.karma > calc_avg_karma(userlist)+5) %}
class="karma-good"{% endif %}>
<!-- This will call user.String() automatically if available: -->
{{ user }}
</h2>
<!-- Will print a human-readable time duration like "3 weeks ago" -->
<p>This user registered {{ user.register_date|naturaltime }}.</p>
<!-- Let's allow the users to write down their biography using markdown;
we will only show the first 15 words as a preview -->
<p>The user's biography:</p>
<p>{{ user.biography|markdown|truncatewords_html:15 }}
<a href="/user/{{ user.id }}/">read more</a></p>
{% if is_admin %}<p>This user is an admin!</p>{% endif %}
</div>
{% endmacro %}
<body>
<!-- Make use of the macro defined above to avoid repetitive HTML code
since we want to use the same code for admins AND members -->
<h1>Our admins</h1>
{% for admin in adminlist %}
{{ user_details(admin, true) }}
{% endfor %}
<h1>Our members</h1>
{% for user in userlist %}
{{ user_details(user) }}
{% endfor %}
</body>
</html>
Latest stable release: v3.0 (go get -u gopkg.in/flosch/pongo2.v3
/ v3
-branch) [read the announcement]
Current development: v4 (master
-branch)
Note: With the release of pongo v4 the branch v2 will be deprecated.
Deprecated versions (not supported anymore): v1
Topic | Status |
---|---|
Django version compatibility: | 1.7 |
Missing (planned) filters: | none (hints) |
Missing (planned) tags: | none (hints) |
Please also have a look on the caveats and on the official add-ons.
- Entirely rewritten from the ground-up.
- Advanced C-like expressions.
- Complex function calls within expressions.
- Easy API to create new filters and tags (including parsing arguments)
- Additional features:
- Macros including importing macros from other files (see template_tests/macro.tpl)
- Template sandboxing (directory patterns, banned tags/filters)
If you're using the master
-branch of pongo2, you might be interested in this section. Since pongo2 is still in development (even though there is a first stable release!), there could be (backwards-incompatible) API changes over time. To keep track of these and therefore make it painless for you to adapt your codebase, I'll list them here.
- Function signature for tag execution changed: not taking a
bytes.Buffer
anymore; insteadExecute()
-functions are now taking aTemplateWriter
interface. - Function signature for tag and filter parsing/execution changed (
error
return type changed to*Error
). INodeEvaluator
has been removed and got replaced byIEvaluator
. You can change your existing tags/filters by simply replacing the interface.- Two new helper functions:
RenderTemplateFile()
andRenderTemplateString()
. Template.ExecuteRW()
is nowTemplate.ExecuteWriter()
Template.Execute*()
functions do now take apongo2.Context
directly (no pointer anymore).
- Write filters / tags (see tutorial) by forking pongo2 and sending pull requests
- Write/improve code tests (use the following command to see what tests are missing:
go test -v -cover -covermode=count -coverprofile=cover.out && go tool cover -html=cover.out
or have a look on gocover.io/github.com/flosch/pongo2) - Write/improve template tests (see the
template_tests/
directory) - Write middleware, libraries and websites using pongo2. :-)
For a documentation on how the templating language works you can head over to the Django documentation. pongo2 aims to be compatible with it.
You can access pongo2's API documentation on godoc.
- pongo2 v3 released
- pongo2 v2 released
- pongo2 1.0 released [August 8th 2014]
- pongo2 playground [August 1st 2014]
- Release of pongo2 1.0-rc1 + pongo2-addons [July 30th 2014]
- Introduction to pongo2 + migration- and "how to write tags/filters"-tutorial. [June 29th 2014]
- date / time: The
date
andtime
filter are taking the Golang specific time- and date-format (not Django's one) currently. Take a look on the format here. - stringformat:
stringformat
does not take Python's string format syntax as a parameter, instead it takes Go's. Essentially{{ 3.14|stringformat:"pi is %.2f" }}
isfmt.Sprintf("pi is %.2f", 3.14)
. - escape / force_escape: Unlike Django's behaviour, the
escape
-filter is applied immediately. Therefore there is no need for aforce_escape
-filter yet.
- for: All the
forloop
fields (likeforloop.counter
) are written with a capital letter at the beginning. For example, thecounter
can be accessed byforloop.Counter
and the parentloop byforloop.Parentloop
. - now: takes Go's time format (see date and time-filter).
- not in-operator: You can check whether a map/struct/string contains a key/field/substring by using the in-operator (or the negation of it):
{% if key in map %}Key is in map{% else %}Key not in map{% endif %}
or{% if !(key in map) %}Key is NOT in map{% else %}Key is in map{% endif %}
.
- ponginae - A web-framework for Go (using pongo2).
- pongo2-tools - Official tools and helpers for pongo2
- pongo2-addons - Official additional filters/tags for pongo2 (for example a markdown-filter). They are in their own repository because they're relying on 3rd-party-libraries.
- beego-pongo2 - A tiny little helper for using Pongo2 with Beego.
- beego-pongo2.v2 - Same as
beego-pongo2
, but for pongo2 v2. - macaron-pongo2 - pongo2 support for Macaron, a modular web framework.
- ginpongo2 - middleware for gin to use pongo2 templates
- pongo2-trans -
trans
-tag implementation for internationalization
Please add your project to this list and send me a pull request when you've developed something nice for pongo2.
Please see the documentation for a full list of provided API methods.
// Compile the template first (i. e. creating the AST)
tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!")
if err != nil {
panic(err)
}
// Now you can render the template with the given
// pongo2.Context how often you want to.
out, err := tpl.Execute(pongo2.Context{"name": "florian"})
if err != nil {
panic(err)
}
fmt.Println(out) // Output: Hello Florian!
package main
import (
"github.com/flosch/pongo2"
"net/http"
)
// Pre-compiling the templates at application startup using the
// little Must()-helper function (Must() will panic if FromFile()
// or FromString() will return with an error - that's it).
// It's faster to pre-compile it anywhere at startup and only
// execute the template later.
var tplExample = pongo2.Must(pongo2.FromFile("example.html"))
func examplePage(w http.ResponseWriter, r *http.Request) {
// Execute the template per HTTP request
err := tplExample.ExecuteWriter(pongo2.Context{"query": r.FormValue("query")}, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/", examplePage)
http.ListenAndServe(":8080", nil)
}
The benchmarks have been run on the my machine (Intel(R) Core(TM) i7-2600 CPU @ 3.40GHz
) using the command:
go test -bench . -cpu 1,2,4,8
All benchmarks are compiling (depends on the benchmark) and executing the template_tests/complex.tpl
template.
The results are:
BenchmarkExecuteComplexWithSandboxActive 50000 60450 ns/op
BenchmarkExecuteComplexWithSandboxActive-2 50000 56998 ns/op
BenchmarkExecuteComplexWithSandboxActive-4 50000 60343 ns/op
BenchmarkExecuteComplexWithSandboxActive-8 50000 64229 ns/op
BenchmarkCompileAndExecuteComplexWithSandboxActive 10000 164410 ns/op
BenchmarkCompileAndExecuteComplexWithSandboxActive-2 10000 156682 ns/op
BenchmarkCompileAndExecuteComplexWithSandboxActive-4 10000 164821 ns/op
BenchmarkCompileAndExecuteComplexWithSandboxActive-8 10000 171806 ns/op
BenchmarkParallelExecuteComplexWithSandboxActive 50000 60428 ns/op
BenchmarkParallelExecuteComplexWithSandboxActive-2 50000 31887 ns/op
BenchmarkParallelExecuteComplexWithSandboxActive-4 100000 22810 ns/op
BenchmarkParallelExecuteComplexWithSandboxActive-8 100000 18820 ns/op
BenchmarkExecuteComplexWithoutSandbox 50000 56942 ns/op
BenchmarkExecuteComplexWithoutSandbox-2 50000 56168 ns/op
BenchmarkExecuteComplexWithoutSandbox-4 50000 57838 ns/op
BenchmarkExecuteComplexWithoutSandbox-8 50000 60539 ns/op
BenchmarkCompileAndExecuteComplexWithoutSandbox 10000 162086 ns/op
BenchmarkCompileAndExecuteComplexWithoutSandbox-2 10000 159771 ns/op
BenchmarkCompileAndExecuteComplexWithoutSandbox-4 10000 163826 ns/op
BenchmarkCompileAndExecuteComplexWithoutSandbox-8 10000 169062 ns/op
BenchmarkParallelExecuteComplexWithoutSandbox 50000 57152 ns/op
BenchmarkParallelExecuteComplexWithoutSandbox-2 50000 30276 ns/op
BenchmarkParallelExecuteComplexWithoutSandbox-4 100000 22065 ns/op
BenchmarkParallelExecuteComplexWithoutSandbox-8 100000 18034 ns/op
Benchmarked on October 2nd 2014.