Можно ли иметь вложенные шаблоны в Go с помощью стандартной библиотеки?


87

Как мне получить вложенные шаблоны, такие как Jinja, во время выполнения Python. TBC я имею в виду, как получить набор шаблонов, унаследованных от базовых шаблонов, просто заполнив их блоками, как это делает Jinja / django-templates. Возможно ли использование только html/templateв стандартной библиотеке.

Если это невозможно, каковы мои альтернативы. Усы, кажется, - вариант, но не упустил ли я тогда такие приятные тонкие функции, html/templateкак контекстно-зависимое экранирование и т. Д.? Какие еще есть альтернативы?

(Среда: Google App Engin, Go runtime v1, Dev - Mac OSx lion)

Спасибо за прочтение.

Ответы:


132

Да, это возможно. html.TemplateФактически A - это набор файлов шаблонов. Если вы выполняете определенный блок в этом наборе, он имеет доступ ко всем другим блокам, определенным в этом наборе.

Если вы создадите карту таких наборов шаблонов самостоятельно, вы получите в основном такую ​​же гибкость, которую предлагает Jinja / Django. Единственное отличие состоит в том, что пакет html / template не имеет прямого доступа к файловой системе, поэтому вам придется анализировать и составлять шаблоны самостоятельно.

Рассмотрим следующий пример с двумя разными страницами («index.html» и «other.html»), которые наследуются от «base.html»:

// Content of base.html:
{{define "base"}}<html>
  <head>{{template "head" .}}</head>
  <body>{{template "body" .}}</body>
</html>{{end}}

// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}

// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}

И следующая карта наборов шаблонов:

tmpl := make(map[string]*template.Template)
tmpl["index.html"] = template.Must(template.ParseFiles("index.html", "base.html"))
tmpl["other.html"] = template.Must(template.ParseFiles("other.html", "base.html"))

Теперь вы можете отобразить свою страницу index.html, вызвав

tmpl["index.html"].Execute("base", data)

и вы можете отобразить свою страницу "other.html", позвонив

tmpl["other.html"].Execute("base", data)

С помощью некоторых уловок (например, согласованного соглашения об именах файлов шаблонов) можно даже tmplавтоматически сгенерировать карту.


3
можно ли иметь данные по умолчанию, например, для «головы»?
— gregghz 06

18
Я просто добавлю сюда то, что мне пришлось вызывать для визуализации фактических шаблонов tmpl["index.html"].ExecuteTemplate(w, "base", data).
— hermansc

base.html анализируется и сохраняется дважды. Вы также можете использовать функцию Clone (), как в golang.org/pkg/text/template/#example_Template_share
— Maarten O.

3
У меня возникают проблемы при передаче данных во вложенный шаблон. Данные из {{ .SomeData }}не будут отображаться во внутреннем шаблоне. Наружные работы.
— 0xAffe

это имеет значение, если template.ParseFiles("index.html", "base.html")есть template.ParseFiles("base.html", "index.html")?
— shackra

10

обратите внимание, когда вы выполняете свой базовый шаблон, вы должны передавать значения дочерним шаблонам, здесь я просто передаю ".", чтобы все было передано вниз.

первый шаблон отображает {{.}}

{{define "base"}}
<html>
        <div class="container">
            {{.}}
            {{template "content" .}}
        </div>
    </body>
</html>
{{end}}

во втором шаблоне отображается {{.domains}}, переданный в родительский.

{{define "content"}}
{{.domains}}
{{end}}

Обратите внимание: если бы мы использовали {{template "content".}} Вместо {{template "content".}}, Домены не были бы доступны из шаблона содержимого.

DomainsData := make(map[string]interface{})
    DomainsData["domains"] = domains.Domains
    if err := groupsTemplate.ExecuteTemplate(w, "base", DomainsData); err != nil {
        http.Error(w, err.Error(), http.StatusInternalServerError)
    }

5
Передача модели - это деталь, на которой я застрял. ;) Спасибо
— Патрик

1
я тоже - Потребовалось немного , чтобы выяснить :)
— РОБЕРТ король

1
Какие! Не могу поверить, что крошечная точка в конце заполнителя {{template}} имела такое большое значение! Почему об этом нигде не упоминается в руководствах или даже в официальной документации Go ?? Я ошеломлен ... но также очень рад, что нашел ваш ответ! Спасибо большое, теперь мои шаблоны с несколькими уровнями вложенности работают красиво!
— Гвинет Ллевелин

Точно то же самое, что я пытался выяснить!
— devforfu

5

поработав с другими пакетами шаблонов, теперь, когда я в основном работаю со стандартным пакетом html / template, думаю, я был наивен, чтобы не оценить простоту, которую он предоставляет, и другие полезности. Я использую очень похожий подход к принятому ответу со следующими изменениями

вам не нужно оборачивать свои макеты дополнительным baseшаблоном, блок шаблона создается для каждого проанализированного файла, поэтому в этом случае он избыточен, мне также нравится использовать действие блока, предусмотренное в новой версии go, что позволяет вам иметь содержимое блока по умолчанию, если вы не предоставляете его в дочерних шаблонах

// base.html
<head>{{block "head" .}} Default Title {{end}}</head>
<body>{{block "body" .}} default body {{end}}</body>

и ваши шаблоны страниц могут быть такими же, как

// Content of index.html:
{{define "head"}}<title>index</title>{{end}}
{{define "body"}}index{{end}}

// Content of other.html:
{{define "head"}}<title>other</title>{{end}}
{{define "body"}}other{{end}}

теперь для выполнения шаблонов вам нужно называть это так

tmpl["index.html"].ExecuteTemplate(os.Stdout, "base.html", data)

4

Используйте Pongo , который представляет собой супернабор шаблонов Go, который поддерживает теги {{extends}} и {{block}} для наследования шаблонов, как и Django.


4

Я возвращался к этому ответу в течение нескольких дней, наконец, укусил пулю и написал для этого небольшой слой абстракции / предварительный процессор. Это в основном:

  • Добавляет ключевое слово extends в шаблоны.
  • Позволяет переопределять вызовы 'define' (таким образом, возможны значения по умолчанию для greggory)
  • Разрешает неопределенные вызовы шаблонов, они просто дают пустую строку
  • Устанавливает значение по умолчанию. в "шаблоне" вызывает. родителя

https://github.com/daemonl/go_sweetpl

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.