È possibile avere modelli nidificati in Go utilizzando la libreria standard?


87

Come ottengo modelli annidati come quelli di Jinja nel runtime di Python. TBC quello che intendo è come faccio a far ereditare un sacco di modelli da un modello di base, semplicemente archiviando in blocchi dei modelli di base, come fa Jinja / django-templates. È possibile utilizzare solo html/templatenella libreria standard.

Se questa non è una possibilità, quali sono le mie alternative. I baffi sembrano essere un'opzione, ma allora mi perderei quelle belle caratteristiche sottili html/templatecome la fuga sensibile al contesto, ecc.? Quali altre alternative ci sono?

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

Grazie per aver letto.

Risposte:


132

Sì, è possibile. A html.Templateè in realtà un insieme di file modello. Se si esegue un blocco definito in questo set, ha accesso a tutti gli altri blocchi definiti in questo set.

Se crei una mappa di tali set di modelli da solo, hai fondamentalmente la stessa flessibilità offerta da Jinja / Django. L'unica differenza è che il pacchetto html / template non ha accesso diretto al file system, quindi devi analizzare e comporre i modelli da solo.

Considera il seguente esempio con due pagine diverse ("index.html" e "other.html") che ereditano entrambe da "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}}

E la seguente mappa di set di modelli:

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

Ora puoi eseguire il rendering della tua pagina "index.html" chiamando

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

e puoi visualizzare la tua pagina "altro.html" chiamando

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

Con alcuni accorgimenti (ad es. Una convenzione di denominazione coerente dei file modello), è persino possibile generare tmplautomaticamente la mappa.


3
è possibile avere dati di default, ad esempio, per "head"?
gregghz

18
Aggiungerò solo qui che per eseguire il rendering dei modelli effettivi ho dovuto chiamare tmpl["index.html"].ExecuteTemplate(w, "base", data).
hermansc

base.html viene analizzato e archiviato due volte. Puoi anche usare la funzione Clone () come in golang.org/pkg/text/template/#example_Template_share
Maarten O.

3
Ho problemi durante il passaggio dei dati a un modello nidificato. I dati di {{ .SomeData }}non verranno visualizzati nel modello interno. Le opere esterne.
0xAffe

importa se lo template.ParseFiles("index.html", "base.html")è template.ParseFiles("base.html", "index.html")?
shackra

10

nota, quando esegui il tuo modello di base, devi passare i valori ai modelli figli, qui passo semplicemente ".", in modo che tutto venga trasmesso.

il modello uno mostra {{.}}

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

il modello due mostra {{.domains}} che è passato al genitore.

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

Nota, se usassimo {{template "content".}} Invece di {{template "content".}}, .Domains non sarebbe accessibile dal modello di contenuto.

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
Trasmettere il modello è un dettaglio su cui sono rimasto bloccato. ;) Grazie
Patrick

1
anche a me - ci è voluto un po 'per capire :)
robert king

1
Che cosa! Non riesco a credere che ci fosse così tanto significato nel piccolo puntino alla fine del segnaposto {{template}}! Perché diavolo non è menzionato da nessuna parte nei tutorial, o anche nella documentazione ufficiale di Go? Sono sbalordito ... ma anche molto felice di aver trovato la tua risposta! Grazie mille, ora i miei modelli con diversi livelli di annidamento funzionano magnificamente!
Gwyneth Llewelyn

Esattamente, la stessa cosa che stavo cercando di capire!
devforfu

5

avendo lavorato con altri pacchetti di template, ora lavoro principalmente con il pacchetto standard html / template, credo di essere stato ingenuo a non apprezzare la semplicità che fornisce e altre chicche. Uso un approccio molto simile alla risposta accettata con le seguenti modifiche

non è necessario avvolgere i layout con un basemodello aggiuntivo , viene creato un blocco modello per ogni file analizzato quindi in questo caso è ridondante, mi piace anche usare l'azione di blocco fornita nella nuova versione di go, che ti permette di avere contenuto del blocco predefinito nel caso in cui non ne venga fornito uno nei modelli figlio

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

e i tuoi modelli di pagina possono essere gli stessi di

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

ora per eseguire i modelli è necessario chiamarlo in questo modo

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

4

Usa Pongo , che è un super-set di modelli Go che supporta i tag {{extends}} e {{block}} per l'ereditarietà dei modelli, proprio come Django.


4

Sono tornato a questa risposta per giorni, finalmente ho morso il proiettile e ho scritto un piccolo strato di astrazione / pre processore per questo. Fondamentalmente:

  • Aggiunge la parola chiave "extends" ai modelli.
  • Consente l'override delle chiamate di "definizione" (quindi sono possibili valori predefiniti per greggory)
  • Consente chiamate "modello" non definite, forniscono solo una stringa vuota
  • Imposta il valore predefinito di. nelle chiamate "modello" a. del genitore

https://github.com/daemonl/go_sweetpl

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.