Czy można mieć zagnieżdżone szablony w Go przy użyciu biblioteki standardowej?

87

Jak uzyskać zagnieżdżone szablony, takie jak Jinja, w środowisku wykonawczym Pythona. TBC mam na myśli to, że mam kilka szablonów dziedziczonych z szablonów podstawowych, po prostu wypełniając bloki szablonów podstawowych, tak jak robi to Jinja / django-templates. Czy można używać tylko html/templatew standardowej bibliotece.

Jeśli to nie jest możliwe, jakie mam alternatywy. Wydaje się, że wąsy są opcją, ale czy wtedy mógłbym przegapić te subtelne cechy, takie html/templatejak kontekstowe uciekanie itp.? Jakie są inne alternatywy?

(Środowisko: Google App Engin, Go runtime v1, Dev - Mac OSx lion)

Dziękuje za przeczytanie.

Sri Kadimisetty
źródło

Odpowiedzi:

132

Tak to mozliwe. A html.Templateto właściwie zestaw plików szablonów. Jeśli wykonasz zdefiniowany blok w tym zestawie, ma on dostęp do wszystkich innych bloków zdefiniowanych w tym zestawie.

Jeśli samodzielnie tworzysz mapę takich zestawów szablonów, masz w zasadzie taką samą elastyczność, jaką oferuje Jinja / Django. Jedyną różnicą jest to, że plik html / template pakiet nie ma bezpośredniego dostępu do systemu plików, więc musisz samodzielnie przeanalizować i skomponować szablony.

Rozważmy następujący przykład z dwiema różnymi stronami („index.html” i „other.html”), które dziedziczą po „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}}

Oraz poniższa mapa zestawów szablonów:

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"))

Możesz teraz renderować swoją stronę „index.html”, dzwoniąc

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

i możesz wyrenderować swoją stronę „other.html”, dzwoniąc

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

Dzięki pewnym sztuczkom (np. Spójnej konwencji nazewnictwa plików szablonów) możliwe jest nawet tmplautomatyczne generowanie mapy.

tux21b
źródło
3
czy można mieć domyślne dane, na przykład dla „głowy”?
gregghz
18
Dodam tylko, że aby wyrenderować rzeczywiste szablony, musiałem wywołać tmpl["index.html"].ExecuteTemplate(w, "base", data).
hermansc
base.html jest analizowany i zapisywany dwukrotnie. Możesz także użyć funkcji Clone (), jak na golang.org/pkg/text/template/#example_Template_share
Maarten O.
3
Mam problemy podczas przekazywania danych do zagnieżdżonego szablonu. Dane z {{ .SomeData }}nie będą wyświetlane w wewnętrznym szablonie. Zewnętrzna działa.
0xAffe
to ma znaczenie, jeśli template.ParseFiles("index.html", "base.html")tak template.ParseFiles("base.html", "index.html")?
shackra
10

uwaga, kiedy wykonujesz swój podstawowy szablon, musisz przekazać wartości do szablonów potomnych, tutaj po prostu przekazuję ".", aby wszystko zostało przekazane.

szablon jeden wyświetla {{.}}

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

szablon dwa wyświetla {{.domains}} przekazane do elementu nadrzędnego.

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

Uwaga, gdybyśmy użyli {{template "content".}} Zamiast {{template "content".}}, Domeny nie byłyby dostępne z szablonu treści.

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)
    }
Robert King
źródło
5
Przekazywanie modelu to szczegół, na którym utknąłem. ;) Dzięki
Patrick
1
ja też - trochę się zastanawiałem :)
robert king
1
Co! Nie mogę uwierzyć, że mała kropka na końcu symbolu zastępczego {{template}} miała tyle znaczenia! Dlaczego, u licha, nie wspomniano o tym nigdzie w samouczkach ani nawet w oficjalnej dokumentacji Go? Jestem zdumiony ... ale też bardzo szczęśliwy, że znalazłem odpowiedź! Dziękuję bardzo, teraz moje szablony z kilkoma poziomami zagnieżdżania działają pięknie!
Gwyneth Llewelyn
Dokładnie, to samo, co próbowałem zrozumieć!
devforfu
5

Pracując z innymi pakietami szablonów, obecnie pracuję głównie ze standardowym pakietem html / template, myślę, że byłem naiwny, nie doceniając prostoty, jaką zapewnia, i innych zalet. Stosuję bardzo podobne podejście do akceptowanej odpowiedzi z następującymi zmianami

nie musisz owijać swoich układów dodatkowym baseszablonem, dla każdego sparsowanego pliku tworzony jest blok szablonu, więc w tym przypadku jest on zbędny, lubię również korzystać z akcji blokowej dostępnej w nowej wersji go, co pozwala na domyślna zawartość bloku na wypadek, gdyby nie podano jej w szablonach podrzędnych

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

a szablony stron mogą być takie same jak

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

teraz, aby wykonać szablony, musisz to tak nazwać

tmpl["index.html"].ExecuteTemplate(os.Stdout, "base.html", data)
allyraza
źródło
4

Użyj Pongo , który jest super zestawem szablonów Go, który obsługuje tagi {{extends}} i {{block}} do dziedziczenia szablonów, tak jak Django.

Obrabować
źródło
4

Wracałem do tej odpowiedzi od wielu dni, w końcu ugryzłem kulę i napisałem małą warstwę abstrakcji / preprocesor do tego. Zasadniczo:

  • Dodaje słowo kluczowe „rozszerza” do szablonów.
  • Umożliwia nadpisywanie wywołań „define” (w ten sposób możliwe są wartości domyślne dla greggory)
  • Zezwala na niezdefiniowane wywołania „szablonu”, po prostu podają pusty ciąg
  • Ustawia domyślną wartość. in 'template' wywołuje. rodzica

https://github.com/daemonl/go_sweetpl

daemonl
źródło