### Complete Pongo2 Web Application Example
Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md
A full Go web application demonstrating Pongo2 template setup, including loader, options, global variables, helper functions, sandbox restrictions, and request handling.
```go
package main
import (
"log"
"net/http"
"time"
"github.com/flosch/pongo2/v7"
)
var templates *pongo2.TemplateSet
func init() {
// Create loader
loader := pongo2.MustNewLocalFileSystemLoader("./templates")
// Create template set
templates = pongo2.NewSet("web", loader)
// Configure options
templates.Options.TrimBlocks = true
templates.Options.LStripBlocks = true
// Set global variables
templates.Globals["site_name"] = "My App"
templates.Globals["current_year"] = time.Now().Year()
// Helper functions
templates.Globals["asset_url"] = func(path string) string {
return "/static/" + path
}
// Sandbox restrictions
templates.BanTag("ssi")
templates.BanTag("include") // Force explicit template paths
}
func handler(w http.ResponseWriter, r *http.Request) {
tpl, err := templates.FromCache("pages/home.html")
if err != nil {
http.Error(w, err.Error(), 500)
return
}
err = tpl.ExecuteWriter(pongo2.Context{
"user": getCurrentUser(r),
"items": getItems(),
}, w)
if err != nil {
log.Printf("Template error: %v", err)
}
}
func main() {
http.HandleFunc("/", handler)
http.ListenAndServe(":8080", nil)
}
```
--------------------------------
### Hello World Example
Source: https://github.com/flosch/pongo2/blob/master/docs/index.md
A simple 'Hello World' example using pongo2's DefaultSet for basic template rendering. Ensure the 'fmt' package is imported for printing the output.
```go
package main
import (
"fmt"
"github.com/flosch/pongo2/v7"
)
func main() {
// These functions use the DefaultSet (convenient for simple use cases)
tpl, _ := pongo2.FromString("Hello {{ name }}!")
out, _ := tpl.Execute(pongo2.Context{"name": "World"})
fmt.Println(out) // Hello World!
}
```
--------------------------------
### Install pongo2
Source: https://github.com/flosch/pongo2/blob/master/docs/index.md
Use go get to install the pongo2 template engine.
```bash
go get -u github.com/flosch/pongo2/v7
```
--------------------------------
### Reusable Filter Package Example
Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md
This example shows how to create a reusable filter package. Filters are registered in the init() function, and the package is imported for its side effects.
```go
// filters/text.go
package filters
import (
"strings"
"unicode"
"github.com/flosch/pongo2/v7"
)
func init() {
pongo2.RegisterFilter("initials", filterInitials)
pongo2.RegisterFilter("slugify", filterSlugify)
pongo2.RegisterFilter("wordcount", filterWordCount)
}
// filterInitials extracts initials from a name.
// Usage: {{ "John Doe"|initials }} -> "JD"
func filterInitials(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) {
words := strings.Fields(in.String())
var initials strings.Builder
for _, word := range words {
if len(word) > 0 {
initials.WriteRune(unicode.ToUpper(rune(word[0])))
}
}
return pongo2.AsValue(initials.String()), nil
}
// filterSlugify converts text to a URL-friendly slug.
// Usage: {{ "Hello World!"|slugify }} -> "hello-world"
func filterSlugify(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) {
s := strings.ToLower(in.String())
var result strings.Builder
lastWasHyphen := true // Prevent leading hyphen
for _, r := range s {
if unicode.IsLetter(r) || unicode.IsDigit(r) {
result.WriteRune(r)
lastWasHyphen = false
} else if !lastWasHyphen {
result.WriteRune('-')
lastWasHyphen = true
}
}
slug := strings.TrimSuffix(result.String(), "-")
return pongo2.AsValue(slug), nil
}
// filterWordCount counts the number of words in text.
// Usage: {{ "Hello World"|wordcount }} -> 2
func filterWordCount(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) {
words := strings.Fields(in.String())
return pongo2.AsValue(len(words)), nil
}
```
```go
// main.go
package main
import (
_ "myapp/filters" // Import for side effects (registers filters)
"github.com/flosch/pongo2/v7"
)
func main() {
tpl := pongo2.Must(pongo2.FromString(
"{{ name|initials }}
{{ title|slugify }}
{{ content|wordcount }} words
"))
// ...
}
```
--------------------------------
### pongo2 Template Example
Source: https://github.com/flosch/pongo2/blob/master/README.md
A basic example demonstrating pongo2's template syntax, including macros, conditional logic, filters, and loops. This template renders user details and lists admins and members.
```django
Our admins and users
{# This is a short example to give you a quick overview of pongo2's syntax. #}
{% macro user_details(user, is_admin=false) %}
= 40) || (user.karma > calc_avg_karma(userlist)+5) %} class="karma-good"{% endif %}>
{{ user }}
This user registered {{ user.register_date|naturaltime }}.
The user's biography:
{{ user.biography|markdown|truncatewords_html:15 }}
read more
{% if is_admin %}
This user is an admin!
{% endif %}
{% endmacro %}
Our admins
{% for admin in adminlist %} {{ user_details(admin, true) }} {% endfor %}
Our members
{% for user in userlist %} {{ user_details(user) }} {% endfor %}
```
--------------------------------
### Quick Start: Compile and Execute a Template
Source: https://github.com/flosch/pongo2/blob/master/LLM.txt
Demonstrates the basic usage of pongo2 to compile a template string and execute it with a given context. Ensure the pongo2 library is imported.
```go
import "github.com/flosch/pongo2/v7"
// Compile and execute a template
tpl, _ := pongo2.FromString("Hello {{ name|capfirst }}!")
out, _ := tpl.Execute(pongo2.Context{"name": "world"})
// Output: Hello World!
```
--------------------------------
### Matching a Specific Keyword
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Example of using `arguments.Match` to check for the presence of a specific keyword token, like 'as'.
```go
if token := arguments.Match(pongo2.TokenKeyword, "as"); token != nil {
// Found "as" keyword
}
```
--------------------------------
### Example pongo2 Template
Source: https://github.com/flosch/pongo2/blob/master/docs/index.md
A comprehensive example of a pongo2 template demonstrating inheritance, blocks, filters, conditional logic, loops, and includes. This template structure is compatible with Django syntax.
```django
{% extends "base.html" %}
{% block title %}{{ page.title }}{% endblock %}
{% block content %}
{{ page.title|title }}
By {{ page.author.name }} on {{ page.date|date:"January 2, 2006" }}
{% if page.tags %}
{% endif %}
{{ page.content|safe }}
{% include "comments.html" with post=page %}
{% endblock %}
```
--------------------------------
### Consume and Navigate Tokens
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Provides methods for inspecting and consuming tokens from the parser's argument list. Use Current() to peek, Consume() to get the next token, ConsumeN() for multiple, and Get() or GetR() for specific positions.
```go
// Get current token without advancing
current := arguments.Current()
// Consume and return current token
token := arguments.Consume()
// Consume N tokens
tokens := arguments.ConsumeN(3)
// Get token at specific index
token := arguments.Get(0) // First token
// Get token from end (negative index)
token := arguments.GetR(-1) // Last token
// Check remaining token count
if arguments.Remaining() > 0 {
// More tokens to parse
}
// Get total token count
count := arguments.Count()
```
--------------------------------
### Serve HTTP Requests with Pongo2 Template Files
Source: https://github.com/flosch/pongo2/blob/master/README.md
This Go example shows how to pre-compile a Pongo2 template from a file at application startup using `pongo2.Must(pongo2.FromFile())` for efficiency. The template is then executed per HTTP request, writing the output directly to the ResponseWriter.
```go
package main
import (
"github.com/flosch/pongo2/v7"
"net/http"
)
var tplExample = pongo2.Must(pongo2.FromFile("example.html"))
func examplePage(w http.ResponseWriter, r *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)
}
```
--------------------------------
### Creating a Secure Custom Template Set
Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md
For production applications, it's recommended to create a custom template set with appropriate security restrictions. This example shows how to use an embedded filesystem loader and ban specific tags and filters.
```go
// For better security, create your own template set:
loader := pongo2.NewFSLoader(embeddedFS) // Use embedded templates
set := pongo2.NewSet("secure", loader)
set.BanTag("include") // Restrict file inclusion
set.BanTag("ssi")
set.BanFilter("safe") // Prevent autoescape bypass
```
--------------------------------
### Using FSLoader with Embedded Filesystem
Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md
This example shows how to use `FSLoader` with Go's `embed.FS` (Go 1.16+) to load templates from embedded files. It requires the `//go:embed` directive.
```go
import "embed"
//go:embed templates/*
var templateFS embed.FS
func main() {
loader := pongo2.NewFSLoader(templateFS)
set := pongo2.NewSet("embedded", loader)
tpl, err := set.FromFile("templates/page.html")
}
```
--------------------------------
### Compile and Execute Pongo2 Template from String
Source: https://github.com/flosch/pongo2/blob/master/README.md
This example demonstrates how to compile a Pongo2 template directly from a string and then execute it with a given context. Ensure error handling for compilation and execution.
```go
tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!")
if err != nil {
panic(err)
}
out, err := tpl.Execute(pongo2.Context{"name": "florian"})
if err != nil {
panic(err)
}
fmt.Println(out) // Output: Hello Florian!
```
--------------------------------
### Write Bytes to Template Output
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Example of writing byte data to the template output using the Write method of TemplateWriter.
```go
func (node *myNode) Execute(ctx *ExecutionContext, writer TemplateWriter) error {
data := []byte("binary data")
writer.Write(data)
return nil
}
```
--------------------------------
### Example Database Template Loader for Pongo2
Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md
A custom `TemplateLoader` implementation that fetches template content from a SQL database. It uses the template name as the identifier and queries a 'templates' table.
```go
type DBLoader struct {
db *sql.DB
}
func (l *DBLoader) Abs(base, name string) string {
return name // Templates are identified by name only
}
func (l *DBLoader) Get(path string) (io.Reader, error) {
var content string
err := l.db.QueryRow("SELECT content FROM templates WHERE name = ?", path).Scan(&content)
if err != nil {
return nil, err
}
return strings.NewReader(content), nil
}
```
--------------------------------
### Write String to Template Output
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Example of writing a simple string to the template output using the WriteString method of TemplateWriter.
```go
func (node *myNode) Execute(ctx *ExecutionContext, writer TemplateWriter) error {
writer.WriteString("Hello, World!")
return nil
}
```
--------------------------------
### Handle Nil Values in Filters
Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md
Filters should gracefully handle nil input values. This example demonstrates returning an empty string when the input is nil.
```go
func filterSafe(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) {
if in.IsNil() {
return pongo2.AsValue(""), nil // Return empty string for nil
}
// ... rest of filter
}
```
--------------------------------
### Pongo2 Template Options Configuration
Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md
Example of configuring template options per-test using `.tpl.options` files. Options like `TrimBlocks` and `LStripBlocks` affect template parsing and rendering.
```text
TrimBlocks=true, LStripBlocks=true
```
--------------------------------
### Render Template from File
Source: https://github.com/flosch/pongo2/blob/master/docs/index.md
Example of rendering a template directly from a file using pongo2's Must and FromFile functions. This method uses the DefaultSet and has unrestricted filesystem access. For production, consider using Template Sets for sandboxing.
```go
// Using DefaultSet (simple, but has unrestricted filesystem access)
tpl := pongo2.Must(pongo2.FromFile("templates/page.html"))
err := tpl.ExecuteWriter(pongo2.Context{
"title": "My Page",
"items": []string{"one", "two", "three"},
}, responseWriter)
```
--------------------------------
### Loading Templates Relative to Base Directory
Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md
When a base directory is specified for `LocalFilesystemLoader`, all template paths are resolved relative to that directory. This example shows loading a template from a subdirectory.
```go
loader := pongo2.MustNewLocalFileSystemLoader("/var/templates")
set := pongo2.NewSet("web", loader)
// Loads /var/templates/pages/home.html
tpl, err := set.FromFile("pages/home.html")
```
--------------------------------
### Matching One of Several Identifiers
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Example of using `arguments.MatchOne` to match an identifier token that can be one of several specified values, like 'asc' or 'desc'.
```go
if token := arguments.MatchOne(pongo2.TokenIdentifier, "asc", "desc"); token != nil {
direction := token.Val // "asc" or "desc"
}
```
--------------------------------
### Template Syntax: Tags
Source: https://github.com/flosch/pongo2/blob/master/LLM.txt
Provides examples of common control flow and structural tags in pongo2, such as conditional statements, loops, template inheritance, and macro definitions.
```django
{% if condition %}...{% elif other %}...{% else %}...{% endif %}
{% for item in items %}...{% empty %}...{% endfor %}
{% block name %}...{% endblock %}
{% extends "base.html" %}
{% include "partial.html" %}
{% macro name(args) %}...{% endmacro %}
```
--------------------------------
### Custom Tag Development Best Practices
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Guidelines and examples for creating robust custom tags in Pongo2, including argument validation, context management, documentation, and edge case handling.
```APIDOC
## Custom Tag Development Best Practices
### 1. Validate Arguments Thoroughly
Check all arguments at parse time to ensure correctness before execution.
```go
func myTagParser(doc *pongo2.Parser, start *pongo2.Token, arguments *pongo2.Parser) (pongo2.INodeTag, error) {
// Check for required arguments
if arguments.Remaining() == 0 {
return nil, arguments.Error("mytag requires at least one argument", nil)
}
// Parse and validate each argument
// ...
// Check for unexpected extra arguments
if arguments.Remaining() > 0 {
return nil, arguments.Error("unexpected extra arguments", nil)
}
return node, nil
}
```
### 2. Use Child Contexts for Scoped Variables
Prevent variable leakage by using child execution contexts for tags that introduce local variables.
```go
func (node *myNode) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) error {
childCtx := pongo2.NewChildExecutionContext(ctx)
childCtx.Private["local_var"] = value
return node.wrapper.Execute(childCtx, writer)
// local_var is not visible in parent context
}
```
### 3. Document Your Tags
Include clear usage examples and argument descriptions in your tag documentation.
```go
// TagCache caches rendered content for a specified duration.
//
// Usage:
// {% cache "key" %}content{% endcache %}
// {% cache key_var 300 %}content{% endcache %}
//
// Arguments:
// - key: Cache key (string or expression)
// - ttl: Optional TTL in seconds (default: 300)
func tagCacheParser(...) { ... }
```
### 4. Handle Edge Cases
Consider and gracefully handle scenarios like empty content, nil values, and type mismatches during tag execution.
```go
func (node *myNode) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) error {
val, err := node.expr.Evaluate(ctx)
if err != nil {
return err
}
// Handle nil
if val.IsNil() {
return nil // Or write default content
}
// Handle wrong type gracefully
if !val.CanSlice() {
ctx.Logf("expected iterable, got %T", val.Interface())
return nil
}
// Handle empty collections
if val.Len() == 0 {
return nil // Nothing to iterate
}
// ... process items
return nil
}
```
### 5. Clean Up Resources
Ensure that any resources acquired by your tag are properly released after execution, typically using `defer`.
```go
func (node *myNode) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) error {
resource := acquireResource()
defer resource.Release()
return node.wrapper.Execute(ctx, writer)
}
```
```
--------------------------------
### Sandbox Pongo2 by Banning Tags
Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md
Restrict template functionality by banning specific tags before loading any templates. This example bans 'include', 'import', 'ssi', and 'extends'.
```go
set := pongo2.NewSet("sandboxed", loader)
// Ban potentially dangerous tags
set.BanTag("include") // Prevent file inclusion
set.BanTag("import") // Prevent macro imports from other files
set.BanTag("ssi") // Prevent server-side includes
set.BanTag("extends") // Prevent template inheritance
// Now load templates - they can't use banned tags
tpl, err := set.FromFile("user-template.html")
```
--------------------------------
### Document Pongo2 Custom Tags
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Provide clear usage examples and argument descriptions in comments for custom tags. This aids users in understanding how to apply the tag correctly.
```go
// TagCache caches rendered content for a specified duration.
//
// Usage:
// {% cache "key" %}content{% endcache %}
// {% cache key_var 300 %}content{% endcache %}
//
// Arguments:
// - key: Cache key (string or expression)
// - ttl: Optional TTL in seconds (default: 300)
func tagCacheParser(...) { ... }
```
--------------------------------
### Common Tasks: Custom Template Loader
Source: https://github.com/flosch/pongo2/blob/master/LLM.txt
Demonstrates how to implement a custom template loader in Go for pongo2 by defining the `Abs` and `Get` methods of the `TemplateLoader` interface. This allows loading templates from custom sources.
```go
type MyLoader struct{}
func (l *MyLoader) Abs(base, name string) string {
return filepath.Join(filepath.Dir(base), name)
}
func (l *MyLoader) Get(path string) (io.Reader, error) {
return os.Open(path)
}
set := pongo2.NewSet("my-set", &MyLoader{})
tpl, _ := set.FromFile("template.html")
```
--------------------------------
### Django Template Syntax for Widget Tag
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Example of how to use the custom 'widget' tag in a Django template, passing named arguments for text, style, and disabled state.
```django
{% widget "button" text="Click me" style="primary" disabled=false %}
```
--------------------------------
### Implement Pongo2 TemplateLoader Interface
Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md
Define custom template loading logic by implementing the `TemplateLoader` interface, which requires `Abs` for path resolution and `Get` for retrieving template content.
```go
type TemplateLoader interface {
// Abs calculates the absolute path to a template
// base is the parent template's path (for includes/extends)
// name is the requested template name
Abs(base, name string) string
// Get returns a reader for the template content
Get(path string) (io.Reader, error)
}
```
--------------------------------
### Internal DefaultSet Initialization
Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md
This code demonstrates the internal initialization process of the DefaultSet, including setting up the default loader and configuration.
```go
DefaultLoader = MustNewLocalFileSystemLoader("")
DefaultSet = NewSet("default", DefaultLoader)
```
--------------------------------
### Initializing LocalFilesystemLoader
Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md
Demonstrates different ways to initialize a `LocalFilesystemLoader`, including specifying a base directory or using the current working directory. The `MustNewLocalFileSystemLoader` variant panics on error.
```go
// Without base directory (uses working directory)
loader, err := pongo2.NewLocalFileSystemLoader("")
// With base directory
loader, err := pongo2.NewLocalFileSystemLoader("/var/templates")
// Panics on error (useful for init)
loader := pongo2.MustNewLocalFileSystemLoader("/var/templates")
```
--------------------------------
### Pongo2 Automatic HTML Escaping Example
Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md
By default, Pongo2 automatically escapes HTML special characters in variable output to prevent XSS attacks. This example shows how user input containing script tags is transformed.
```django
{{ user_input }}
```
```html
<script>alert('xss')</script>
```
--------------------------------
### Template Rendering from File with HTTP Server
Source: https://context7.com/flosch/pongo2/llms.txt
Load templates from the filesystem and pre-compile them at startup for performance. Execute templates directly to an http.ResponseWriter.
```go
package main
import (
"github.com/flosch/pongo2/v7"
"net/http"
)
// Pre-compile templates at startup using Must() helper
var tplExample = pongo2.Must(pongo2.FromFile("templates/example.html"))
func examplePage(w http.ResponseWriter, r *http.Request) {
// Execute template directly to ResponseWriter
err := tplExample.ExecuteWriter(pongo2.Context{
"query": r.FormValue("query"),
"user": getCurrentUser(r),
}, w)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/", examplePage)
http.ListenAndServe(":8080", nil)
}
```
--------------------------------
### Count Words in String
Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md
Use the `wordcount` filter to get the total number of words in a string.
```django
{{ "Hello World"|wordcount }}
```
--------------------------------
### Configure Template Loaders for Different Sources
Source: https://context7.com/flosch/pongo2/llms.txt
Set up template loading from local disk, embedded filesystems, or Go's `fs.FS` interface. Multiple loaders can be combined in a set, and new loaders can be added dynamically.
```go
package main
import (
"embed"
"os"
"github.com/flosch/pongo2/v7"
)
//go:embed templates/*
var embeddedTemplates embed.FS
func main() {
// LocalFilesystemLoader - load from disk
fsLoader := pongo2.MustNewLocalFileSystemLoader("/var/templates")
// FSLoader - load from Go's fs.FS interface (embed.FS, os.DirFS, etc.)
embedLoader := pongo2.NewFSLoader(embeddedTemplates)
dirLoader := pongo2.NewFSLoader(os.DirFS("/var/templates"))
// Multiple loaders - tries each in order
set := pongo2.NewSet("multi", fsLoader, embedLoader)
set.AddLoader(dirLoader) // Add more loaders later
// Template resolution tries loader1 first, then loader2, etc.
tpl, err := set.FromFile("page.html")
if err != nil {
panic(err)
}
out, _ := tpl.Execute(pongo2.Context{})
println(out)
}
```
--------------------------------
### Render Template from File
Source: https://github.com/flosch/pongo2/blob/master/docs/getting-started.md
Pre-compile templates from files at startup for better performance in web applications. Handle execution errors by returning an HTTP error.
```go
package main
import (
"github.com/flosch/pongo2/v7"
"net/http"
)
// Pre-compile templates at startup for better performance
var tplExample = pongo2.Must(pongo2.FromFile("templates/example.html"))
func examplePage(w http.ResponseWriter, r *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)
}
```
--------------------------------
### Creating and Configuring a Custom Template Set
Source: https://github.com/flosch/pongo2/blob/master/docs/template-sets.md
This snippet shows how to create a new template set with a specific loader, configure its properties like debug mode and global variables, and then load a template from this set.
```go
// Create a new set with a loader
loader := pongo2.MustNewLocalFileSystemLoader("/path/to/templates")
mySet := pongo2.NewSet("email-templates", loader)
// Configure the set
mySet.Debug = true
mySet.Globals["company_name"] = "ACME Corp"
// Load templates from this set
tpl, err := mySet.FromFile("welcome.html")
```
--------------------------------
### Check if Built-in Filter Exists
Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md
Provides an example of checking if a filter is registered as a built-in filter using the BuiltinFilterExists function.
```go
if pongo2.BuiltinFilterExists("myfilter") {
// Filter is available
}
```
--------------------------------
### Register a Custom Filter
Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md
Register a custom filter using `pongo2.RegisterFilter` within an `init()` function. This example registers a 'double' filter.
```go
package main
import "github.com/flosch/pongo2/v7"
func init() {
pongo2.RegisterFilter("double", filterDouble)
}
func filterDouble(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) {
return pongo2.AsValue(in.Integer() * 2), nil
}
```
--------------------------------
### Testing: Command Line Interface
Source: https://github.com/flosch/pongo2/blob/master/LLM.txt
Shows the basic commands for running tests and benchmarks for the pongo2 project using Go's built-in testing tools.
```bash
# Run all tests
go test ./...
# Run specific test
go test -run TestFilterEscape ./...
# Run benchmarks
go test -bench=. -benchmem ./...
```
--------------------------------
### Convert String to List of Characters
Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md
Use the `make_list` filter to convert a string into a list where each element is a single character. This example iterates through the characters.
```django
{% for char in "hello"|make_list %}{{ char }}-{% endfor %}
```
--------------------------------
### Template Execution Methods
Source: https://context7.com/flosch/pongo2/llms.txt
Demonstrates various methods for executing templates, including returning strings, byte slices, writing to io.Writers (buffered and unbuffered), and executing specific blocks.
```go
package main
import (
"bytes"
"fmt"
"github.com/flosch/pongo2/v7"
"os"
)
func main() {
tpl, _ := pongo2.FromString("Hello {{ name }}!")
ctx := pongo2.Context{"name": "World"}
// Returns rendered template as string
out, _ := tpl.Execute(ctx)
fmt.Println(out)
// Returns rendered template as []byte
bytesOut, _ := tpl.ExecuteBytes(ctx)
fmt.Println(string(bytesOut))
// Writes to io.Writer (buffered, safe on error)
var buf bytes.Buffer
_ = tpl.ExecuteWriter(ctx, &buf)
fmt.Println(buf.String())
// Writes to io.Writer (unbuffered, faster but partial output on error)
_ = tpl.ExecuteWriterUnbuffered(ctx, os.Stdout)
// Execute specific blocks only (for partial rendering)
blockTpl, _ := pongo2.FromString(`
{% block header %}Header Content{% endblock %}
{% block content %}Main Content{% endblock %}
{% block footer %}Footer Content{% endblock %}
`)
blocks, _ := blockTpl.ExecuteBlocks(ctx, []string{"header", "content"})
fmt.Println(blocks["header"]) // "Header Content"
fmt.Println(blocks["content"]) // "Main Content"
}
```
--------------------------------
### Run Benchmarks in Go
Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md
Execute all benchmarks in the current module and display memory allocation statistics. Use for performance analysis.
```bash
go test -bench=. -benchmem ./...
```
--------------------------------
### Split String into List
Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md
Use the `split` filter to divide a string into a list based on a delimiter. This example shows iterating over the resulting list.
```django
{% for part in "a,b,c"|split:"," %}{{ part }}{% endfor %}
```
--------------------------------
### Get a random element from a list
Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md
The `random` filter selects and returns a single, arbitrary element from a list. This is useful for displaying varied content.
```django
{{ items|random }}
```
--------------------------------
### Capture and Transform Output with Buffer
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Demonstrates capturing template output into a buffer, transforming it (e.g., to uppercase), and then writing the transformed content.
```go
func (node *myNode) Execute(ctx *ExecutionContext, writer TemplateWriter) error {
var buf bytes.Buffer
// Execute wrapped content into buffer
err := node.wrapper.Execute(ctx, &buf)
if err != nil {
return err
}
// Transform the captured content
transformed := strings.ToUpper(buf.String())
// Write transformed content
writer.WriteString(transformed)
return nil
}
```
--------------------------------
### Basic Template Rendering from String
Source: https://context7.com/flosch/pongo2/llms.txt
Compile a template from a string and execute it with a context to produce output. Ensure error handling for compilation and execution.
```go
package main
import (
"fmt"
"github.com/flosch/pongo2/v7"
)
func main() {
// Compile the template from a string
tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!")
if err != nil {
panic(err)
}
// Execute with context - can be called multiple times
out, err := tpl.Execute(pongo2.Context{"name": "florian"})
if err != nil {
panic(err)
}
fmt.Println(out) // Output: Hello Florian!
}
```
--------------------------------
### Sandbox Pongo2 by Banning Filters
Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md
Restrict template functionality by banning specific filters before loading any templates. This example bans the 'safe' and 'escapejs' filters.
```go
set := pongo2.NewSet("restricted", loader)
// Ban filters that bypass security
set.BanFilter("safe") // Prevent bypassing autoescape
// Ban filters based on your security requirements
set.BanFilter("escapejs") // If you don't want JS output
```
--------------------------------
### Peeking N Tokens Ahead
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Shows how to use `arguments.PeekN` to look ahead a specified number of tokens (e.g., 1 token ahead) to check for a specific type and value (e.g., '=').
```go
if token := arguments.PeekN(1, pongo2.TokenSymbol, "="); token != nil {
// Token after next is "="
}
```
--------------------------------
### Template Filters
Source: https://github.com/flosch/pongo2/blob/master/docs/getting-started.md
Transform variable output using filters. Examples include converting to uppercase, truncating words, formatting numbers, and joining elements.
```django
{{ name|upper }}
{{ text|truncatewords:30 }}
{{ price|floatformat:2 }}
{{ items|join:", " }}
```
--------------------------------
### Macro Recursion Example
Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md
Illustrates a macro that calls itself, which Pongo2 protects against by limiting recursion depth to prevent stack overflows. Exceeding the limit results in an error.
```django
{% macro infinite() %}
{{ infinite() }} {# This will eventually fail #}
{% endmacro %}
```
--------------------------------
### Load Template from Cache
Source: https://github.com/flosch/pongo2/blob/master/docs/getting-started.md
Use `FromCache` to load templates, which improves performance by avoiding recompilation on each request. This is recommended for production environments.
```go
tpl, err := pongo2.FromCache("templates/page.html")
```
--------------------------------
### Peeking for a Specific Keyword and Value
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Shows how to use `arguments.Peek` to inspect the next token for a specific keyword and value ('as') without consuming it.
```go
if token := arguments.Peek(pongo2.TokenKeyword, "as"); token != nil {
// Next token is "as" (not consumed)
}
```
--------------------------------
### Get the length of a list or string
Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md
The `length` filter returns the number of elements in a list or the number of characters in a string. It's a fundamental filter for sequence manipulation.
```django
{{ items|length }}
```
```django
{{ "hello"|length }} {# 5 #}
```
--------------------------------
### Valid and Invalid Context Keys in Pongo2
Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md
Context keys must be valid identifiers. Invalid keys, such as those starting with quotes or containing hyphens/dots, will cause a panic.
```go
// Valid
ctx := pongo2.Context{
"user": user,
"item_1": item,
}
// Invalid - will panic
ctx := pongo2.Context{
"'invalid": value, // Can't start with quote
"foo-bar": value, // Can't contain hyphen
"foo.bar": value, // Can't contain dot
}
```
--------------------------------
### Compare Benchmarks with Benchstat
Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md
Compare benchmark results using `benchstat`. This requires running benchmarks multiple times and saving the output to files for comparison.
```bash
go test -bench=. -benchmem -count=10 > old.txt
# make changes
go test -bench=. -benchmem -count=10 > new.txt
benchstat old.txt new.txt
```
--------------------------------
### Render Template from String
Source: https://github.com/flosch/pongo2/blob/master/docs/getting-started.md
Compile and execute a template directly from a string. Ensure error handling for compilation and execution.
```go
package main
import (
"fmt"
"github.com/flosch/pongo2/v7"
)
func main() {
// Compile the template
tpl, err := pongo2.FromString("Hello {{ name|capfirst }}!")
if err != nil {
panic(err)
}
// Execute with context
out, err := tpl.Execute(pongo2.Context{"name": "florian"})
if err != nil {
panic(err)
}
fmt.Println(out) // Output: Hello Florian!
}
```
--------------------------------
### Matching a String Token
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Example of using `arguments.MatchType` to check if the next token is a string and retrieve its value. The value returned is the string content without the surrounding quotes.
```go
if token := arguments.MatchType(pongo2.TokenString); token != nil {
value := token.Val // The string content (without quotes)
}
```
--------------------------------
### Create Isolated Template Set
Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md
Create a new `TemplateSet` for isolated template groups, shared globals, and sandboxing. Use `NewSet()` for distinct configurations.
```go
NewSet()
```
--------------------------------
### Macro Returning Safe String
Source: https://github.com/flosch/pongo2/blob/master/docs/macros.md
Macros return their rendered content as a safe string, meaning HTML is not escaped by default. This example shows a simple bold tag.
```django
{% macro bold(text) %}
{{ text }}
{% endmacro %}
{{ bold("Hello") }} {# Output: Hello #}
```
--------------------------------
### Run All Tests in Go
Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md
Execute all tests within the current Go module. Ensure all tests pass before committing.
```bash
go test ./...
```
--------------------------------
### Create Custom Pongo2 Template Set
Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md
Avoid using the default convenience functions for production. Instead, create a custom template set with either an embedded filesystem loader for maximum security or a local filesystem loader with specific sandbox restrictions.
```go
// Instead of using pongo2.FromFile() (which uses DefaultSet), do this:
// Option 1: Use embedded templates (most secure)
//go:embed templates/*
var templateFS embed.FS
loader := pongo2.NewFSLoader(templateFS)
set := pongo2.NewSet("secure", loader)
// Option 2: Use LocalFilesystemLoader with sandbox restrictions
loader := pongo2.MustNewLocalFileSystemLoader("/var/templates")
set := pongo2.NewSet("restricted", loader)
set.BanTag("include") // Prevent file inclusion
set.BanTag("import") // Prevent macro imports
set.BanTag("ssi") // Prevent server-side includes
set.BanTag("extends") // Prevent template inheritance
set.BanFilter("safe") // Prevent autoescape bypass
// Now use the custom set
tpl, err := set.FromFile("page.html")
```
--------------------------------
### Get the last element of a list or string
Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md
Use the `last` filter to retrieve the final element from a list or the last character of a string. This is helpful for accessing the end of a sequence.
```django
{{ items|last }}
```
```django
{{ "hello"|last }} {# o #}
```
--------------------------------
### Get the first element of a list or string
Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md
The `first` filter returns the initial element from a list or the first character of a string. It's useful for accessing the beginning of a sequence.
```django
{{ items|first }}
```
```django
{{ "hello"|first }} {# h #}
```
--------------------------------
### Run Tests with Verbose Output
Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md
Execute tests and display detailed output for each test case. Helpful for understanding test execution flow.
```bash
go test -v ./...
```
--------------------------------
### Validate Filter Parameters
Source: https://github.com/flosch/pongo2/blob/master/docs/write_filters.md
Always validate filter parameters to ensure they meet requirements. This example checks if a length parameter is provided and is non-negative, returning a *pongo2.Error if validation fails.
```go
func filterTruncate(in *pongo2.Value, param *pongo2.Value) (*pongo2.Value, error) {
if param.IsNil() {
return nil, &pongo2.Error{
Sender: "filter:truncate",
OrigError: errors.New("truncate requires a length parameter"),
}
}
length := param.Integer()
if length < 0 {
return nil, &pongo2.Error{
Sender: "filter:truncate",
OrigError: errors.New("length must be non-negative"),
}
}
// ... rest of filter
}
```
--------------------------------
### Registering a Custom Tag
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Demonstrates how to register a new custom tag named 'mytag' with its corresponding parser function. Ensure the tag name is unique to avoid conflicts.
```go
func init() {
err := pongo2.RegisterTag("mytag", myTagParser)
if err != nil {
panic(err) // Tag name already exists
}
}
```
--------------------------------
### Pongo2 Execution Flow
Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md
Illustrates the Pongo2 template processing pipeline, from template string to final output.
```text
Template String → Lexer → Tokens → Parser → AST (INode tree) → Execute → Output
```
--------------------------------
### Lint Code with Golangci-Lint
Source: https://github.com/flosch/pongo2/blob/master/CLAUDE.md
Run `golangci-lint` for comprehensive code linting. This tool aggregates multiple linters to enforce style and catch potential issues.
```bash
golangci-lint run
```
--------------------------------
### LocalFileSystemLoader Path Resolution
Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md
Demonstrates how LocalFileSystemLoader resolves paths. Note that the base directory is for path resolution only and not a security feature. Absolute paths bypass it.
```go
// The base directory is for path resolution, NOT security
loader := pongo2.MustNewLocalFileSystemLoader("/var/templates")
set := pongo2.NewSet("app", loader)
// Relative paths are resolved from the base directory
tpl, _ := set.FromFile("pages/home.html") // Loads /var/templates/pages/home.html
// WARNING: Absolute paths bypass the base directory entirely
tpl, _ := set.FromFile("/etc/passwd") // This would work if not restricted!
```
--------------------------------
### Matching One of Several Symbols
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Demonstrates using `arguments.MatchOne` to match a symbol token that can be one of several options, such as an opening parenthesis or bracket.
```go
if token := arguments.MatchOne(pongo2.TokenSymbol, "(", "["); token != nil {
opener := token.Val
}
```
--------------------------------
### Pongo2 Parser Argument Matching Methods
Source: https://github.com/flosch/pongo2/blob/master/docs/custom-extensions.md
Illustrates various methods available on the `arguments` parser for matching specific token types, keywords, identifiers, and expressions. Useful for defining custom tag syntax.
```go
// Match specific token type and value
if token := arguments.Match(pongo2.TokenKeyword, "as"); token != nil {
// Matched "as" keyword
}
// Match any of several values
if token := arguments.MatchOne(pongo2.TokenIdentifier, "asc", "desc"); token != nil {
// Matched either "asc" or "desc"
}
// Match by type only
if token := arguments.MatchType(pongo2.TokenString); token != nil {
value := token.Val
}
if token := arguments.MatchType(pongo2.TokenNumber); token != nil {
// ...
}
if token := arguments.MatchType(pongo2.TokenIdentifier); token != nil {
name := token.Val
}
// Parse a full expression
expr, err := arguments.ParseExpression()
// Check remaining arguments
if arguments.Remaining() > 0 {
return nil, arguments.Error("Too many arguments", nil)
}
// Peek without consuming
if arguments.Peek(pongo2.TokenSymbol, "=") != nil {
// Next token is "="
}
```
--------------------------------
### Extract a slice from a list
Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md
The `slice` filter extracts a portion of a list based on start and end indices, similar to Python's slicing. Negative indices count from the end.
```django
{{ items|slice:":2" }}
```
```django
{{ items|slice:"1:" }}
```
```django
{{ items|slice:"1:3" }}
```
```django
{{ items|slice:"-2:" }}
```
--------------------------------
### Basic Filter Usage
Source: https://github.com/flosch/pongo2/blob/master/docs/filters.md
Demonstrates the basic syntax for applying filters to variables, including filters with and without arguments, and chaining multiple filters.
```django
{{ value|filtername }}
```
```django
{{ value|filtername:argument }}
```
```django
{{ value|filter1|filter2|filter3 }}
```
--------------------------------
### Macro Avoiding Context Access
Source: https://github.com/flosch/pongo2/blob/master/docs/macros.md
This example contrasts a macro that relies on implicit context (`bad_header`) with one that explicitly accepts arguments (`good_header`), highlighting the latter's improved reusability.
```django
{# Avoid: Relies on implicit context #}
{% macro bad_header() %}
{{ page_title }}
{% endmacro %}
{# Better: Explicit argument #}
{% macro good_header(title) %}
{{ title }}
{% endmacro %}
{{ good_header(page_title) }}
```
--------------------------------
### Creating Child Execution Contexts in Pongo2
Source: https://github.com/flosch/pongo2/blob/master/docs/custom-extensions.md
Demonstrates how to create a new child execution context using `pongo2.NewChildExecutionContext` for tags that require their own variable scope, such as loops.
```go
func (node *myNode) Execute(ctx *pongo2.ExecutionContext, writer pongo2.TemplateWriter) error {
// Create child context (inherits parent's variables)
childCtx := pongo2.NewChildExecutionContext(ctx)
// Add scoped variables
childCtx.Private["loop_var"] = someValue
// Execute wrapped content with child context
return node.wrapper.Execute(childCtx, writer)
}
```
--------------------------------
### Pongo2 Store Position for Error Reporting
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Best practice for custom Pongo2 tags: store the start token of the tag to provide accurate error reporting with line and column numbers.
```go
type myTagNode struct {
position *pongo2.Token // For error reporting
// ... other fields
}
```
--------------------------------
### Common Tasks: Adding a Custom Filter
Source: https://github.com/flosch/pongo2/blob/master/LLM.txt
Provides a Go code example for registering a custom filter with pongo2. The filter function receives input and parameter values and returns a transformed value.
```go
func init() {
pongo2.RegisterFilter("myfilter", func(in, param *pongo2.Value) (*pongo2.Value, error) {
// Transform in.String() and return new Value
return pongo2.AsValue(result), nil
})
}
```
--------------------------------
### Tag Parser Function Signature
Source: https://github.com/flosch/pongo2/blob/master/docs/write_tags.md
Defines the signature for a custom tag parser function, which receives the document parser, the starting token, and an argument parser. It returns a compiled tag node or an error.
```go
func myTagParser(doc *Parser, start *Token, arguments *Parser) (INodeTag, error)
```
--------------------------------
### Custom Secure Loader Implementation
Source: https://github.com/flosch/pongo2/blob/master/docs/security-sandboxing.md
Implement a custom loader that enforces additional security restrictions, such as checking file extensions and ensuring paths stay within an allowed directory.
```go
type SecureLoader struct {
baseDir string
allowedExt []string
}
func (l *SecureLoader) Abs(base, name string) string {
// Resolve path relative to base directory
resolved := filepath.Join(filepath.Dir(base), name)
// Ensure result is within allowed directory
if !strings.HasPrefix(resolved, l.baseDir) {
return "" // Return empty to indicate not found
}
return resolved
}
func (l *SecureLoader) Get(path string) (io.Reader, error) {
// Check file extension
ext := filepath.Ext(path)
allowed := false
for _, e := range l.allowedExt {
if ext == e {
allowed = true
break
}
}
if !allowed {
return nil, fmt.Errorf("file extension not allowed: %s", ext)
}
return os.Open(path)
}
```