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.

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.


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

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)

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.


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

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.