표준 라이브러리를 사용하여 Go에서 중첩 된 템플릿을 가질 수 있습니까?


87

Python 런타임에서 Jinja와 같은 중첩 템플릿을 얻으려면 어떻게해야합니까? TBC가 의미하는 바는 Jinja / django-templates처럼 기본 템플릿의 블록으로 파일을 작성하여 기본 템플릿에서 여러 템플릿을 상속받는 방법입니다. html/template표준 라이브러리 에서만 사용할 수 있습니까?

그것이 가능성이 아니라면 내 대안은 무엇입니까? 콧수염은 옵션 인 것 같지만 html/template상황에 맞는 이스케이프와 같은 멋진 미묘한 기능을 놓치고 있습니까? 다른 대안은 무엇입니까?

(환경 : Google App Engin, Go 런타임 v1, Dev-Mac OSx lion)

읽어 주셔서 감사합니다.

답변:


132

네 가능합니다. A html.Template는 실제로 템플릿 파일 집합입니다. 이 세트에서 정의 된 블록을 실행하면이 세트에 정의 된 다른 모든 블록에 액세스 할 수 있습니다.

이러한 템플릿 세트의 맵을 직접 생성하면 기본적으로 Jinja / Django가 제공하는 것과 동일한 유연성을 갖게됩니다. 유일한 차이점은 html / template 패키지는 파일 시스템에 직접 액세스 할 수 없으므로 직접 템플릿 을 구문 분석하고 구성해야한다는 것입니다.

둘 다 "base.html"에서 상속되는 두 개의 다른 페이지 ( "index.html"및 "other.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}}

다음 템플릿 세트 맵 :

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

이제 다음을 호출하여 "index.html"페이지를 렌더링 할 수 있습니다.

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

다음을 호출하여 "other.html"페이지를 렌더링 할 수 있습니다.

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

몇 가지 트릭 (예 : 템플릿 파일의 일관된 이름 지정 규칙)을 사용하면 tmpl지도를 자동으로 생성 할 수도 있습니다 .


3
예를 들어 "head"에 대한 기본 데이터를 가질 수 있습니까?
gregghz

18
여기서 호출해야하는 실제 템플릿을 렌더링하기 위해 여기에 추가하겠습니다 tmpl["index.html"].ExecuteTemplate(w, "base", data).
hermansc

base.html은 두 번 구문 분석되고 저장됩니다. golang.org/pkg/text/template/#example_Template_share
Maarten O.

3
중첩 템플릿에 데이터를 전달할 때 문제가 있습니다. 의 데이터 {{ .SomeData }}는 내부 템플릿에 표시되지 않습니다. 외부가 작동합니다.
0xAffe

경우는 중요 template.ParseFiles("index.html", "base.html")하다 template.ParseFiles("base.html", "index.html")?
shackra

10

기본 템플릿을 실행할 때 하위 템플릿에 값을 전달해야합니다. 여기서는 "."를 전달하여 모든 것이 전달되도록합니다.

템플릿 1에 {{.}} 표시

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

템플릿 2는 상위에 전달 된 {{.domains}}를 표시합니다.

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

{{template "content".}} 대신 {{template "content".}}를 사용한 경우 콘텐츠 템플릿에서 .domains에 액세스 할 수 없습니다.

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
모델을 물려받는 것은 제가 집착 한 디테일입니다. ;) 감사합니다
Patrick

1
나 너무 - :) 알아 내기 위해 조금했다
로버트 왕

1
뭐! {{template}} 자리 표시 자 끝에있는 작은 점에 너무 많은 의미가 있다는 것을 믿을 수 없습니다! 도대체 왜 튜토리얼이나 공식 Go 문서에서 언급되지 않습니까 ?? 나는 놀라움을 금치 못했지만 ... 당신의 답을 찾아서 매우 기쁩니다! 감사합니다. 이제 여러 수준의 중첩이있는 템플릿이 아름답게 작동합니다!
Gwyneth Llewelyn

정확히, 제가 알아 내려고했던 것과 똑같은 것입니다!
devforfu

5

다른 템플릿 패키지로 작업 한 후, 지금은 주로 표준 html / 템플릿 패키지로 작업하고 있는데, 그것이 제공하는 단순함과 다른 장점에 감사하지 않는 것이 순진하다고 생각합니다. 나는 다음과 같은 변경 사항으로 수락 된 답변에 매우 유사한 접근 방식을 사용합니다.

추가 base템플릿으로 레이아웃을 래핑 할 필요가 없습니다. 파싱 ​​된 모든 파일에 대해 템플릿 블록이 생성되므로이 경우에는 중복됩니다. 새로운 버전의 go에서 제공하는 블록 액션을 사용하여 하위 템플릿에 제공하지 않는 경우 기본 블록 콘텐츠

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

페이지 템플릿은 다음과 같을 수 있습니다.

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

이제 템플릿을 실행하려면 다음과 같이 호출해야합니다.

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

4

Django와 마찬가지로 템플릿 상속을 위해 {{extends}} 및 {{block}} 태그를 지원하는 Go 템플릿의 상위 집합 인 Pongo를 사용 합니다.


4

나는 며칠 동안이 대답으로 돌아 왔고 마침내 총알을 깨물고 이것을 위해 작은 추상화 계층 / 사전 프로세서를 작성했습니다. 기본적으로 :

  • 템플릿에 '확장'키워드를 추가합니다.
  • '정의'호출 재정의 허용 (따라서 greggory에 대한 기본값이 가능함)
  • 정의되지 않은 '템플릿'호출을 허용하며 빈 문자열 만 제공합니다.
  • 의 기본값을 설정합니다. '템플릿'에서. 부모의

https://github.com/daemonl/go_sweetpl

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.