web-dev-qa-db-fra.com

Est-il possible d'avoir des modèles imbriqués dans Go en utilisant la bibliothèque standard? (Google App Engine)

Comment puis-je obtenir des modèles imbriqués comme celui de Jinja dans le runtime Python. Ce que je veux dire par TBC, c’est comment puis-je avoir un tas de modèles hérités d’un modèle de base, il suffit de les archiver par blocs, comme le fait Jinja/Django-templates. Est-il possible d'utiliser seulement html/template dans la bibliothèque standard.

Si ce n’est pas une possibilité, quelles sont mes alternatives? Moustache semble être une option, mais est-ce que je raterais alors ces jolies fonctionnalités subtiles de html/template, telles que l'échappement sensible au contexte, etc.? Quelles sont les autres alternatives?

(Environnement: Google App Engin, Go runtime v1, Dev - Lion Mac OSx)

Merci d'avoir lu.

78
sri

Oui c'est possible. Un html.Template est en réalité un ensemble de fichiers de modèle. Si vous exécutez un bloc défini dans cet ensemble, il aura accès à tous les autres blocs définis dans cet ensemble.

Si vous créez vous-même une carte de ces ensembles de modèles, vous disposez de la même souplesse que celle offerte par Jinja/Django. La seule différence est que le paquet html/template n'a pas d'accès direct au système de fichiers. Vous devez donc analyser et composer vous-même les modèles.

Considérez l'exemple suivant avec deux pages différentes ("index.html" et "other.html") dont les deux héritent 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}}

Et la carte suivante des ensembles de modèles:

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

Vous pouvez maintenant afficher votre page "index.html" en appelant 

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

et vous pouvez rendre votre page "other.html" en appelant

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

Avec quelques astuces (par exemple, une convention de dénomination cohérente de vos fichiers de modèle), il est même possible de générer automatiquement la mappe tmpl.

120
tux21b

remarque, lorsque vous exécutez votre modèle de base, vous devez transmettre des valeurs aux modèles enfants. Ici, je passe simplement ".", afin que tout soit transmis.

le modèle 1 affiche {{.}}

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

le modèle deux affiche {{.domains}} transmis au parent.

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

Notez que si nous utilisions {{modèle "contenu".}} Au lieu de {{modèle "contenu".}}, Les domaines .domains ne seraient pas accessibles à partir du modèle de contenu.

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

Utilisez Pongo , qui est un super ensemble de modèles Go prenant en charge les balises {{extend}} et {{block}} pour l'héritage de modèles, à l'instar de Django.

5
Rob

Cela fait des jours que je reviens à cette réponse, j'ai finalement mordu la balle et écrit un petit processeur/couche d'abstraction pour cela. C'est fondamentalement:

  • Ajoute le mot clé 'extend' aux modèles.
  • Permet de remplacer les appels 'define' (ainsi, les valeurs par défaut pour greggory sont possibles)
  • Autorise les appels de "modèles" non définis, ils donnent juste une chaîne vide
  • Définit la valeur par défaut de. dans 'modèle' appelle à. du parent

https://github.com/daemonl/go_sweetpl

4
daemonl

ayant travaillé avec d’autres modèles de paquetages, j’ai travaillé la plupart du temps avec des paquets html/template standard. J’ai été naïf de ne pas apprécier la simplicité qu’il procure et d’autres avantages. J'utilise une approche très similaire à la réponse acceptée avec les modifications suivantes

vous n'avez pas besoin d'encapsuler vos mises en page avec un modèle base supplémentaire, un bloc de modèle est créé pour chaque fichier analysé. Dans ce cas, il est redondant. J'aime également utiliser l'action de blocage fournie dans la nouvelle version de go, qui vous permet de: avoir un contenu de bloc par défaut au cas où vous n'en fourniriez pas dans les modèles enfants

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

et vous les modèles de page peuvent être les mêmes que

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

maintenant pour exécuter les modèles dont vous avez besoin de l'appeler comme si 

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