flosch
pongo2
Go

Django-syntax like template-engine for Go

Last updated Jul 6, 2026
3.1k
Stars
284
Forks
65
Issues
+4
Stars/day
Attention Score
83
Language breakdown
No language data available.
Files click to expand
README

pongo2

PkgGoDev Build Status Run on Repl.it

pongo2 is a Django-syntax like templating-language (official website).

Install/update using go get (no dependencies required by pongo2):

go get -u github.com/flosch/pongo2/v7

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!).

:question: Looking for a Go developer/consultant? I'm available for hire. :mantechnologist:

First impression of a template

<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 userdetails(user, isadmin=false) %}
  <div class="user_item">
    <!-- Let's indicate a user's good karma -->
    <h2 {% if (user.karma>= 40) || (user.karma > calcavgkarma(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>

Documentation

Features

- Macros including importing macros from other files (see template_tests/macro.tpl) - Template sandboxing (directory patterns, banned tags/filters)

Caveats

Filters

  • date / time: The date and time 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" }} is fmt.Sprintf("pi is %.2f", 3.14).
  • escape / forceescape: Unlike Django's behaviour, the escape-filter is applied immediately. Therefore there is no need for a forceescape-filter yet.

Tags

  • for: All the forloop fields (like forloop.counter) are written with a capital letter at the beginning. For example, the counter can be accessed by forloop.Counter and the parentloop by forloop.Parentloop.
  • now: takes Go's time format (see date and time-filter).

Misc

  • 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 %}.

Add-ons, libraries and helpers

Official

  • 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.

3rd-party

Please add your project to this list and send me a pull request when you've developed something nice for pongo2.

Who's using pongo2

I'm compiling a list of pongo2 users. Add your project or company!

API-usage examples

Please see the documentation for a full list of provided API methods.

A tiny example (template string)

// 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!

Example server-usage (template file)

package main

import ( "github.com/flosch/pongo2/v7" "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) }

🔗 More in this category

© 2026 GitRepoTrend · flosch/pongo2 · Updated daily from GitHub