Golang from Python

Articles with the templates tag

Go HTML Templates: Functions and Flow

Here's a Jinja2 template I ported to Go:

{% for user in users %}
<input type="checkbox"
       name="users"
       value="{{ user.guid }}"
       id="user-{{ user.guid }}"
       {% if user.guid in selected_users %} checked{% endif %}>
<label for="user-{{ user.guid }}">{{ user.name }}</label>
{% endfor %}

It renders a checkbox list of users, some of whom are pre-selected. I'm going to focus on the test {% if user.guid in selected_users %}. In Python, I passed a list of guids, and was done. There's no generic Go function for "slice contains," so I tried some silly things - first, I tried to register a template function.

Actually registering the function was easy: call Template.Funcs before parsing your templates, with a mapping of strings to your new functions. I gave up on this approach because the most generic contains function I could write would only work on []string containers. Since I couldn't make something globally useful, I tried passing a contains function to the template itself:

var ctx struct{
    Users []db.User
    Selected func(string)bool
}
ctx.Users, err = listUsers() // error handling left to the imagination
ctx.Selected = func(guid string) {
    for _, u := range selectedUsers {
        if u == guid {
            return true
        }
    }

    return false
}

templates.ExecuteTemplate(w, "form.html", ctx)

This had more promise — calling the function looked like this: {{ if index $.Selected .Guid }}. It worked, but ultimately, it was less clear than a map[string]bool, and more code. The test {{ if index .Map $key }} treats missing keys as false, so you only need to fill in the true keys.

In the Go code above, you can see that I'm rendering templates by applying them to anonymous structs. It's concise if you only call the template once; for templates I have to reuse (mostly forms), unexported structs work well.

Go HTML Templates: Applying Data

The last post on structuring Go templates left out the main feature of templating: varying output. Let's look at my header.html again:

<html>
<head><title>{{ . }}</title></head>
<body>

{{ . }} means "put the value of . here." So, if you apply that template to the string "Index", it outputs <title>Index</title>. The same goes for structs; if you apply a template to a struct{Title string}, {{ .Title }} prints the title field.

There's one catch with using ., and the solution was deep enough in the docs that I missed it completely. Here's something that might look right, but isn't:

type Folder struct {
    Name string
    Files []string
}

f := Folder{"/root", []string{".bash_history", ".bashrc"}}

// It's not okay to ignore errors... unless you're a blog post.
tmpl, _ := template.New("t").Parse(
    `Contents of {{ .Name }}:
    {{ range _, $f := .Files }}
        {{ .Name }}/{{ $f }}
    {{ end }}
    `)
tmpl.Execute(os.Stdout, f)

This doesn't work, because . changes in context of a range, to refer to the current list element. The fix is easy, but it's buried a few pages down in the docs: $ always holds the original value of .. Here's the correct template (or run it on play.golang.org):

`Contents of {{ .Name }}:
{{ range .Files }}
    {{ $.Name }}/{{ . }}
{{ end }}`

here's another context in which . changes — when you invoke another template. Earlier, I applied index.html to a Go string with {{ template "header.html" "Index" }}. This works the same way as applying templates to values in Go code. For a small project, passing a string works great. For a larger project, I expect to pass a larger struct into my header and footer to include CSS and JavaScript files that are needed on each page, rather than a static list in the header.

In the next post, I'll look at functions and control flow. Go templates have a stricter separation between code and formatting, and it's the biggest departure from working with Jinja2.

Go HTML Templates: Not Jinja2

My first impression of Go's template system was pretty rough — and to understand why, let's talk about Jinja2. To make a page in Python, I inherit most of the structure from a base template:

{# base.html #}
<html>
<head><title>{% block title %}OVERRIDE THIS{% endblock %}</title></head>
<body>

{% block content %}{% endblock %}
</body></html>

If I wanted to write an index.html, I'd start from base.html and override the sections marked with {% block %} and {% endblock %} tags:

{# index.html #}
{% extends "base.html" %}

{% block title %}Index{% endblock %}

{% block content %}
This is the index page!
{% endblock %}

When you render a template that extends another, it takes the base content and fills in any blocks overridden in the children. So, rendering index.html would look like:

<html>
<head><title>Index</title></head>
<body>

This is the index page!
</body></html>

Go's template system is not like that.

It took me back to my time with PHP — which is the last thing I ever expected to say about Go. To render a page with common scaffolding in html/template, you break base.html up into a header and footer, and include them at the top and bottom:

header.html:

<html>
<head><title>{{ . }}</title></head>
<body>

footer.html:

</body></html>

index.html:

{{ template "header.html" "Index" }}

This is the index page!

{{ template "footer.html" }}

This felt like a step back: Jinja2's blocks took time to learn, but they let you build HTML content in a way that made total sense — write elements, and slot them into place. Go's template system is less abstract — to add a common header, you put a {{ template "header.html" }} exactly where you want it to show up.

While I miss Jinja2's abstractions, I've also started to appreciate the directness of Go's templates. In the next post, I talk a bit about how Go applies templates to values — it's also very different from Jinja2, and (like many things in the Go standard library) as you get into the details, Go's choices start making more sense.