É possível ter modelos aninhados no Go usando a biblioteca padrão?

87

Como obtenho modelos aninhados como o Jinja tem no tempo de execução do python. TBC, o que quero dizer é como eu tenho um monte de modelos herdados de modelos básicos, apenas arquivando em blocos dos modelos básicos, como o Jinja / django-templates faz. É possível usar apenas html/templatena biblioteca padrão.

Se isso não for uma possibilidade, quais são as minhas alternativas. O bigode parece ser uma opção, mas eu estaria perdendo esses recursos sutis legais, html/templatecomo o escape sensível ao contexto, etc.? Que outras alternativas existem?

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

Obrigado pela leitura.

Sri Kadimisetty
fonte

Respostas:

132

Sim, é possível. A html.Templateé na verdade um conjunto de arquivos de modelo. Se você executar um bloco definido neste conjunto, ele terá acesso a todos os outros blocos definidos neste conjunto.

Se você criar um mapa desses conjuntos de modelos por conta própria, terá basicamente a mesma flexibilidade que o Jinja / Django oferece. A única diferença é que o pacote html / template não tem acesso direto ao sistema de arquivos, então você precisa analisar e compor os modelos por conta própria.

Considere o seguinte exemplo com duas páginas diferentes ("index.html" e "other.html") que herdam de "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 o seguinte mapa de conjuntos de modelos:

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

Agora você pode renderizar sua página "index.html" chamando

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

e você pode renderizar sua página "other.html" chamando

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

Com alguns truques (por exemplo, uma convenção de nomenclatura consistente para seus arquivos de modelo), é até possível gerar o tmplmapa automaticamente.

tux21b
fonte
3
é possível ter dados padrão, por exemplo, para "cabeça"?
gregghz
18
Vou apenas adicionar aqui para renderizar os modelos reais que tive que chamar tmpl["index.html"].ExecuteTemplate(w, "base", data).
hermansc
base.html é analisado e armazenado duas vezes. Você também pode usar a função Clone () como em golang.org/pkg/text/template/#example_Template_share
Maarten O.
3
Estou tendo problemas ao passar dados para um modelo aninhado. Os dados de {{ .SomeData }}não serão exibidos no modelo interno. O exterior funciona.
0xAffe
importa se template.ParseFiles("index.html", "base.html")é template.ParseFiles("base.html", "index.html")?
shackra de
10

note, quando você executa seu template base, você deve passar os valores para os templates filhos, aqui eu simplesmente passo ".", para que tudo seja passado.

o modelo um exibe {{.}}

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

o modelo dois exibe {{.domains}} que é passado para o pai.

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

Observe, se usássemos {{template "content".}} Em vez de {{template "content".}}, .Domains não seria acessível a partir do template de conteúdo.

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
fonte
5
Repassar o modelo é um detalhe em que fiquei preso. ;) Obrigado
Patrick,
1
eu também - demorei um pouco para descobrir :)
robert king
1
O que! Eu não posso acreditar que havia tanto significado no pequeno ponto no final do marcador de posição {{template}}! Por que diabos isso não é mencionado em nenhum lugar dos tutoriais, ou mesmo na documentação oficial do Go ?? Estou pasmo ... mas também muito feliz por ter encontrado sua resposta! Muito obrigado, agora meus modelos com vários níveis de aninhamento funcionam perfeitamente!
Gwyneth Llewelyn
Exatamente, a mesma coisa que eu estava tentando descobrir!
devforfu
5

tendo trabalhado com outros pacotes de modelo, hoje em dia eu trabalho principalmente com o pacote html / template padrão, acho que fui ingênuo por não apreciar a simplicidade que ele oferece e outras vantagens. Eu uso uma abordagem muito semelhante para resposta aceita com as seguintes alterações

você não precisa embrulhar seus layouts com um basemodelo adicional , um bloco de modelo é criado para cada arquivo analisado, então, neste caso, é redundante, eu também gosto de usar a ação de bloqueio fornecida na nova versão do go, que permite que você tenha conteúdo de bloco padrão no caso de você não fornecer um em modelos filhos

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

e seus modelos de página podem ser os mesmos

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

agora para executar os modelos você precisa chamá-lo assim

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

Use Pongo , que é um superconjunto de modelos Go que suporta as tags {{extends}} e {{block}} para herança de template, assim como o Django.

Roubar
fonte
4

Eu tenho voltado a esta resposta há dias, finalmente mordi a bala e escrevi uma pequena camada de abstração / pré-processador para isso. Basicamente:

  • Adiciona a palavra-chave 'extends' aos modelos.
  • Permite substituir chamadas 'definir' (portanto, os valores padrão para greggory são possíveis)
  • Permite chamadas de 'modelo' não definidas, elas apenas fornecem uma string vazia
  • Define o valor padrão de. em 'template' chama para. do pai

https://github.com/daemonl/go_sweetpl

demônio
fonte