장고 템플릿에서 "블록"을 반복하는 방법


126

동일한 장고 템플릿에서 동일한 {% 블록 %}을 (를) 두 번 사용하고 싶습니다 . 이 블록이 기본 템플릿에 두 번 이상 나타나기를 원합니다.

# base.html
<html>
    <head>
        <title>{% block title %}My Cool Website{% endblock %}</title>
    </head>
    <body>
        <h1>{% block title %}My Cool Website{% endblock %}</h1>
    </body>
</html>

그런 다음 확장하십시오.

# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}

# pictures.html
{% extends 'base.html' %}
{% block title %}My Pictures{% endblock %}

# cats.html
{% extends 'base.html' %}
{% block title %}My Cats{% endblock %}

Django가 블록을 한 번만 표시하기를 원하므로 예외가 발생합니다.

/의 TemplateSyntaxError

이름이 'title'인 'block'태그가 두 번 이상 나타납니다.

빠르고 더러운 해결책은 블록 제목title1title2 로 복제하는 것입니다 .

# blog.html
{% extends 'base.html' %}
{% block title1 %}My Blog{% endblock %}
{% block title2 %}My Blog{% endblock %}

그러나 이것은 DRY 원칙을 위반하는 것입니다. 상속 템플릿이 많고 지옥에 가고 싶지 않기 때문에 매우 어려울 것입니다. ;-)

이 문제에 대한 트릭이나 해결 방법이 있습니까? 모든 코드를 복제하지 않고 템플릿에서 동일한 블록을 어떻게 반복 할 수 있습니까?


1
또한이 질문에 대한 솔루션을 참조하십시오 stackoverflow.com/q/1178743/168034
phunehehe

2
이 답변은 특히 phunehehe와 관련된 질문에 대한 답변을 참조하십시오 .
Tobu

답변:


69

이 경우 컨텍스트 프로세서를 사용하는 것이 과도하다고 생각합니다. 당신은 이것을 쉽게 할 수 있습니다 :

#base.html
<html>
    <head>
        <title>{% block title %}My Cool Website{% endblock %}</title>
    </head>
    <body>
        {% block content %}{% endblock %}
    </body>
</html>

그리고:

# blog.html
{% extends 'base.html' %}
{% block content %}
    <h1>{% block title %}My Blog{% endblock %}</h1>
    Lorem ipsum here...
{% endblock %}

등등 ... DRY- 호환되는 것처럼 보입니다.


1
나는 내일 이것을 시도 할 수있다-나는 템플릿에서 약간의 반복을 저장하는 방법을 궁금해하고 있으며 이것은 좋은 접근법처럼 보인다. 감사.
thebiglife

1
이 방법은 훌륭합니다. base.html을 base.html과 superbase.html로 분리 했으므로 공유 템플릿에 표준 제목 마크 업 (예 : h1)을 넣으려는 경우에도 작동합니다. 페이지는 여전히 제목 블록의 내용을 무시할 수 있으며 두 위치 모두에서 업데이트됩니다.
SystemParadox

2
이것은 텍스트를 두 번 이상 사용할 수 없습니까?
Dennis Golomazov

1
Denis Golomazov : 아니요.이 경우 매크로 플러그인을 사용하는 것이 좋습니다 (아래 참조).
dqd

1
정의하는 : 또한 주변의 다른 방법으로 적용 할 수 있습니다 h1정의 블록 내부 컨텐츠를 title. 아니면 A 동 정의하는 부분 의를 title.
Mikael Lindlöf

83

Django 템플릿 매크로 플러그인을 사용하십시오.

https://gist.github.com/1715202 (django> = 1.4)

또는

http://www.djangosnippets.org/snippets/363/ (django <1.4)

장고> = 1.4

# base.html
{% kwacro title %}
    {% block title %}My Cool Website{% endblock %}
{% endkwacro %}

<html>
    <head>
        <title>{% usekwacro title %}</title>
    </head>
    <body>
        <h1>{% usekwacro title %}</h1>
    </body>
</html>

# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}

장고 <1.4

# base.html
{% macro title %}
    {% block title %}My Cool Website{% endblock %}
{% endmacro %}

<html>
    <head>
        <title>{% usemacro title %}</title>
    </head>
    <body>
        <h1>{% usemacro title %}</h1>
    </body>
</html>

# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}

2
환상적이다! 이것은 django 루프와 ajax 데이터 루프와 템플릿을 공유함으로써 얻는 문제를 실제로 정리할 수 있습니다.
글리세린

1
좋은 해결책입니다. 그러나 "use_macro"입니다. "usemacro"가 잘못되었습니다.
Ramtin

기본적으로 장고에 내장되어 있어야합니다.
zepp.lee 8:15에

19

실제로 블록을 사용하고 싶지 않고 변수를 사용하고 싶을 것입니다.

# base.html
<html>
    <head>
        <title>{{ title|default:"My Cool Website" }}</title>
    </head>
    <body>
        <h1>{{ title|default:"My Cool Website" }}</h1>
    </body>
</html>

그런 다음 컨텍스트를 통해 제목을 설정하십시오.


17
아마 건조합니다. 그러나 뷰 내에서 제목을 설정하고 싶지 않을 것입니다. 그러나 템플릿에서.
Lakshman Prasad

6
제목은 컨텍스트 내에서 제공되지 않고 템플릿 내에서 설정해야합니다.이 "title"변수를 정의 할 방법이 있어야합니다. 그렇지 않으면 좋은 해결책이 아닙니다.
기 illa Esquevin

django 관리 템플릿이 {{title}}에 대해하는 일이지만 제거시 제목을 정의하는 것은 불편합니다.
Tobu

13

내가 똑같은 일을 할 때 내가 발견 한 방법은 다음과 같습니다.

# base_helper.html
<html>
    <head>
        <title>{% block _title1 %}{% endblock %}</title>
    </head>
    <body>
        <h1>{% block _title2 %}{% endblock %}</h1>
    </body>
</html>


# base.html
{% extends "base_helper.html" %}

# Copy title into _title1 & _title2, using "My Cool Website" as a default.
{% block _title1 %}{% block _title2 %}{% block title %}My Cool Website{% endblock %}{% endblock %}{% endblock %}

불행히도 추가 파일이 필요하지만보기에서 제목을 전달할 필요는 없습니다.


결국 나는 새 파일이 필요없는 {% macro %} 솔루션에 정착했으며, 전반적으로 표현하고자하는 것을 정확하게 표현할 수 있습니다.
Roman Starkov

단순하고 효율적입니다. @dqd의 답변과 달리 블록은 중첩 될 필요가 없으며 다른 헤드 속성과 동일한 내용을 가질 수있는 페이스 북 및 태그에 매우 유용합니다. 공감!
벤츠 지

2
좋은 대답입니다. base를 상속하는 각 템플릿에서 <h1> 태그를 반복 할 필요가 없기 때문에 @dqd의 답변보다 DRYer 인 것 같습니다. 이것은 대답이 될 수 있습니다.
Anupam

우수한! 나는 테이블의 바닥 글 행을 맨 위로 반복하려는보다 복잡한 시나리오에서 이것을 사용했습니다. 그리고 <tr>행은 다소 복잡했습니다.
caram


5

논의는 여기에 있습니다 : http://code.djangoproject.com/ticket/4529을 분명히 그들은 이것이 일반적인 사용 시나리오 아니라고 생각하기 때문에 핵심 팀이 티켓을 거부 장고, 그러나 나는 동의하지 않는다.

반복 블록은 다음과 같이 간단하고 깔끔하게 구현됩니다. https://github.com/SmileyChris/django-repeatblock

템플릿 매크로는 또 하나이지만 저자는 신중하게 테스트하지 않았다고 언급했습니다. http://www.djangosnippets.org/snippets/363/

반복 블록을 사용했습니다.


4
원래 django-repeatblock 저장소가 삭제 된 것 같습니다. 그것의 가장 좋은 포크는 github.com/phretor/django-repeatblock 인 것 같습니다 . 또한 github.com/ydm/django-sameas 를 찾았 습니다 .'wontfix 'Django 패치가 필요하지 않습니다.
natevw

4

장고 - 매크로,이 건너 오는 사람에 대한 업데이 트로서, 내가 위에서 언급 한 조각을 찍은 및 템플릿 태그 라이브러리로 설정되어, 매크로가 더 강력하게하고 명시 적으로 반복 블록 패턴을 구현 장고 - 매크로 .


4

위의 템플릿 태그 답변 do_set과 비슷한 경량 솔루션이 do_get있습니다. Django를 사용하면 전체 템플릿 컨텍스트를 글로벌 변수를 정의 할 수있는 태그로 전달할 수 있습니다.

base.html :

<!DOCTYPE html>
<html lang="en">
<head>
  {% block head %}
    <title>{{ title }}</title>
  {% endblock %}
</head>
<body>
  <h1>{{ title }}</h1>
</body>
</html>

page.html :

{% extends "base.html" %}

{% block head %}
  {% define 'title' 'Homepage | title' %}
  {{ block.super }}
{% endblock %}

맞춤 태그 (여기에서 아이디어를 얻으십시오 : https://stackoverflow.com/a/33564990/2747924 ) :

@register.simple_tag(takes_context=True)
def define(context, key, value):
    context.dicts[0][key] = value
    return ''

또한 {% load %}사용자 정의 태그를 잊지 말고 템플릿 옵션 내장 목록에 추가하여 모든 템플릿에로드 할 필요는 없습니다. {% define %}하위 템플릿은 상위 태그와 일치하는 블록 태그 만 렌더링하므로이 접근 방식의 유일한 제한 은 블록 태그 내에서 호출해야한다는 것입니다. 그 주위에 방법이 있는지 확실하지 않습니다. 또한 define통화를 분명하게 사용하기 전에 전화가 오도록하십시오.


3

Van Gale의 제안을 바탕으로 templatetags.py 파일에 다음을 추가하여 get 및 set 태그를 만들 수 있습니다.

register = template.Library()

Stateful = {}
def do_set(parser, token):
    _, key = token.split_contents()
    nodelist = parser.parse(('endset',))
    parser.delete_first_token()  # from the example -- why?
    return SetStatefulNode(key,nodelist)

class SetStatefulNode(template.Node):
    def __init__(self, key, nodes):
        Stateful[key] = nodes
    def render(self, context):
        return ''
register.tag('set', do_set)

def do_get(parser, token):
    tag_name, key = token.split_contents()
    return GetStatefulNode(key)

class GetStatefulNode(template.Node):
    def __init__(self, key):
       self.key = key
    def render(self, context):
        return ''.join( [x.render(context) for x in Stateful[self.key]] )

register.tag('get', do_get)

그런 다음 한 템플릿에서 값을 설정하고 다른 템플릿을 통해 값을 {% set foo %}put data here{% endset %}가져옵니다 {% get foo %}.


나는 그것이 가장 우아한 해결책이라고 생각합니다. Kieran과 Van Gale에게 감사드립니다!
Robert Lacroix

꽤 매끄럽지 만 Set 태그에 모든 노드를 렌더링하는 것이 더 좋을 것 같습니다. 그렇지 않으면 Get에 의해 반복해서 렌더링됩니다. 좋은 생각 일 수있는 이유 (페이지의 다른 블록 내부에 동일한 저장된 블록을 렌더링)를 생각할 수는 있지만 방금 지적했다고 생각했습니다.
acjay

3

나는 또한 템플릿 파일에서 반복되는 {% block %}에 대한 동일한 요구를 겪었다. 문제는 Django 조건부 중 어느 경우에도 Django {% block %}을 (를) 사용하기를 원하고 현재 파일을 확장 할 수있는 후속 파일에서 {% block %}을 (를) 덮어 쓸 수 있기를 원한다는 것입니다. (이 경우 내가 기술적으로 재사용하지 않기 때문에 내가 원하는 것은 분명히 변수보다 더 많은 블록입니다. 조건의 양쪽 끝에 나타납니다.

문제 :

다음 Django 템플릿 코드는 템플릿 구문 오류가 발생하지만 조건부에서 정의 된 {% 블록 %}을 (를) 재사용하는 것이 유효한 "원합니다"라고 생각합니다. 조건부로만 TRUTHY 조건을 확인해서는 안됩니까?)

# This example shows a {{ DEBUG }} conditional that loads 
#   Uncompressed JavaScript files if TRUE 
#   and loads Asynchronous minified JavaScript files if FALSE.  

# BASE.html
{% if DEBUG %}
    <script src="{{MEDIA_URL}}js/flatfile.1.js"></script>
    <script src="{{MEDIA_URL}}js/flatfile.2.js"></script>
    <script src="{{MEDIA_URL}}js/flatfile.3.js"></script>
    <script type="text/javascript">
        {% block page_js %}
            var page = new $site.Page();
        {% endblock page_js %}
    </script>
{% else %}
    <script type="text/javascript">
        // load in the PRODUCTION VERSION of the site
        // minified and asynchronosly loaded
        yepnope([
            {
                load : '{MEDIA_URL}}js/flatfiles.min.js',
                wait : true,
                complete : function() {
                    {% block page_js %} // NOTE THE PAGE_JS BLOCK
                        var page = new $site.Page();
                    {% endblock page_js %}
                }
            }
        )];
    </script>
{% endif %}

# ABOUT.html
{% extends 'pages/base.html' %}
{% block page_js %}
var page = new $site.Page.About();
{% endblock page_js %}

해결책:

{% include %}를 사용하여 {% block %}을 (를) 조건부로 두 번 이상 삽입 할 수 있습니다. 장고 구문 검사기에 TRUTHY {% include %} 만 포함되어 있기 때문에 이것은 나를 위해 일했습니다. 아래 결과를보십시오 :

# partials/page.js
{% block page_js %}
    var page = new $site.Page();    
{% endblock %}

# base.html
{% if DEBUG %}
    <script src="{{MEDIA_URL}}js/flatfile.1.js"></script>
    <script src="{{MEDIA_URL}}js/flatfile.2.js"></script>
    <script src="{{MEDIA_URL}}js/flatfile.3.js"></script>
    <script type="text/javascript">
        {% include 'partials/page_js.html' %}
    </script>
{% else %}
    <script type="text/javascript">
        yepnope([
            {
                load : '{MEDIA_URL}}js/flatfiles.min.js',
                wait : true,
                complete : function() {
                    {% include 'partials/page_js.html' %}
                }
            }
        )];
    </script>
{% endif %}

2

나는 이 답변 을 사용 하여 물건을 건조하게 유지합니다.

{% extends "base.html" %}

{% with "Entry Title" as title %}
    {% block title %}{{ title }}{% endblock %}
    {% block h1 %}{{ title }}{% endblock %}
{% endwith %}

1

이를위한 두 가지 쉬운 솔루션이 있습니다.

가장 쉬운 방법은 제목을 컨텍스트 변수에 넣는 것입니다. 뷰에서 컨텍스트 변수를 설정합니다.

일반보기와 같은 것을 사용하고 있고 그림, 고양이 등을위한 views.py가없는 경우 컨텍스트에서 변수를 설정하는 사용자 정의 템플릿 태그를 사용할 수 있습니다 .

이 경로를 사용하면 다음과 같은 작업을 수행 할 수 있습니다.

{% extends "base.html" %}
{% load set_page_title %}
{% page_title "My Pictures" %}
...

그런 다음 base.html에서

...
{% block title %}{{ page_title }}{% endblock %}
...
<h1>{{ page_title }}</h1>

그러나Any variable set in the context will only be available in the same block of the template in which it was assigned. This behavior is intentional; it provides a scope for variables so that they don’t conflict with context in other blocks.
Jonathan

0

선택한 답변은 하위 템플릿의 한 태그를 다른 태그 안에 감싸서 동일한 값을 제공하는 쉬운 해결 방법을 암시합니다. 나는 이것을 소셜 이미지에 사용합니다.

자식 템플릿 :

{% extends 'base.html' %}
...
{% block meta_image %}
{% block meta_image_secure %}
{% if object.cover_pic %}
{{ object.cover_pic.url }}
{% else %}
https://live-static.welovemicro.com/static/img/device-dark.png
{% endif %}
{% endblock %}
{% endblock %}
...

그런 다음 부모님 base.html:

...
<meta property="og:image" itemprop="image" content="{% block meta_image %}https://live-static.welovemicro.com/static/img/device-dark.png{% endblock %}">
<meta property="og:image:secure_url" itemprop="image" content="{% block meta_image_secure %}https://live-static.welovemicro.com/static/img/device-dark.png{% endblock %}">
...

-3

에서 나뭇 가지 당신은이 같이 할 수 있습니다 :

# base.html
<html>
    <head>
        <title>{{ block('title') }}</title>
    </head>
    <body>
        <h1>{{ block('title') }}</h1>
    </body>
</html>

# blog.html
{% extends 'base.html' %}
{% block title %}My Blog{% endblock %}

# pictures.html
{% extends 'base.html' %}
{% block title %}My Pictures{% endblock %}

# cats.html
{% extends 'base.html' %}
{% block title %}My Cats{% endblock %}

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