Apakah mungkin memiliki templat bersarang di Go menggunakan pustaka standar?


88

Bagaimana cara mendapatkan template bersarang seperti yang dimiliki Jinja di runtime python. TBC yang saya maksud adalah bagaimana saya memiliki sekumpulan template yang diwarisi dari template dasar, hanya dengan memasukkan blok template dasar, seperti yang dilakukan Jinja / django-templates. Apakah mungkin menggunakan hanya html/templatedi perpustakaan standar.

Jika itu tidak memungkinkan, apa alternatif saya. Kumis tampaknya menjadi pilihan tetapi apakah saya akan kehilangan fitur halus yang bagus html/templateseperti pelarian sensitif konteks, dll.? Alternatif lain apa yang ada?

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

Terima kasih sudah membaca.

Jawaban:


133

Ya itu mungkin. A html.Templatesebenarnya adalah sekumpulan file template. Jika Anda menjalankan blok yang ditentukan dalam himpunan ini, ia memiliki akses ke semua blok lain yang ditentukan dalam himpunan ini.

Jika Anda membuat peta set templat seperti itu sendiri, pada dasarnya Anda memiliki fleksibilitas yang sama dengan yang ditawarkan Jinja / Django. Perbedaan satu-satunya adalah paket html / template tidak memiliki akses langsung ke sistem file, jadi Anda harus mengurai dan membuat template sendiri.

Pertimbangkan contoh berikut dengan dua halaman berbeda ("index.html" dan "other.html") yang keduanya diwarisi dari "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}}

Dan peta set template berikut:

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

Sekarang Anda dapat merender halaman "index.html" dengan memanggil

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

dan Anda dapat merender halaman "other.html" dengan memanggil

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

Dengan beberapa trik (misalnya, konvensi penamaan yang konsisten dari file template Anda), tmplpeta dapat dibuat secara otomatis.


3
apakah mungkin memiliki data default, misalnya, untuk "head"?
gregghz

18
Saya hanya akan menambahkan di sini untuk membuat template sebenarnya yang harus saya panggil tmpl["index.html"].ExecuteTemplate(w, "base", data).
hermansc

base.html diurai dan disimpan dua kali. Anda juga dapat menggunakan fungsi Clone () seperti di golang.org/pkg/text/template/#example_Template_share
Maarten O.

3
Saya mengalami masalah saat mengirimkan data ke template bersarang. Data dari {{ .SomeData }}tidak akan ditampilkan di templat bagian dalam. Pekerjaan luar.
0xAffe

itu penting jika template.ParseFiles("index.html", "base.html")ini template.ParseFiles("base.html", "index.html")?
shackra

10

Catatan, saat Anda menjalankan template dasar, Anda harus meneruskan nilai ke template anak, di sini saya hanya meneruskan ".", sehingga semuanya diturunkan.

template satu menampilkan {{.}}

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

template dua menampilkan {{.domains}} yang diteruskan ke induknya.

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

Perhatikan, jika kami menggunakan {{template "content".}} Dan bukan {{template "content".}}, .Domains tidak akan bisa diakses dari template konten.

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
Meneruskan model adalah detail yang membuat saya terjebak. ;) Terima kasih
Patrick

1
saya juga - mengambil sedikit untuk mencari tahu :)
robert king

1
Apa! Saya tidak percaya bahwa ada begitu banyak makna di titik kecil kecil di akhir placeholder {{template}}! Mengapa tidak disebutkan di mana pun di tutorial, atau bahkan dokumentasi resmi Go ?? Saya terperangah ... tetapi juga sangat senang menemukan jawaban Anda! Terima kasih banyak, sekarang templat saya dengan beberapa level bersarang berfungsi dengan baik!
Gwyneth Llewelyn

Persis, hal yang sama yang saya coba cari tahu!
devforfu

5

setelah bekerja dengan paket template lain, sekarang hari saya kebanyakan bekerja dengan paket html / template standar, saya rasa saya naif untuk tidak menghargai kesederhanaan yang diberikannya dan barang lainnya. Saya menggunakan pendekatan yang sangat mirip untuk menerima jawaban dengan perubahan berikut

Anda tidak perlu membungkus tata letak Anda dengan basetemplat tambahan , blok templat dibuat untuk setiap file yang diurai jadi dalam hal ini berlebihan, saya juga suka menggunakan tindakan blokir yang disediakan dalam versi baru go, yang memungkinkan Anda untuk memilikinya konten blokir default jika Anda tidak menyediakannya di template anak

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

dan templat halaman Anda bisa sama dengan

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

sekarang untuk menjalankan templat Anda perlu memanggilnya seperti itu

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

4

Gunakan Pongo , yang merupakan himpunan super dari Template Go yang mendukung tag {{extends}} dan {{block}} untuk pewarisan template, seperti Django.


4

Saya telah kembali ke jawaban ini selama berhari-hari, akhirnya menggigit peluru dan menulis lapisan abstraksi kecil / prosesor pra untuk ini. Ini pada dasarnya:

  • Menambahkan kata kunci 'meluas' ke template.
  • Memungkinkan penimpaan panggilan 'definisikan' (sehingga nilai default untuk greggory dimungkinkan)
  • Mengizinkan panggilan 'template' yang tidak ditentukan, mereka hanya memberikan string kosong
  • Setel nilai default. dalam panggilan 'template' ke. dari orang tua

https://github.com/daemonl/go_sweetpl

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.