Bir django şablonunda bir "blok" nasıl tekrarlanır


126

Aynı django şablonunda aynı {% block%} iki kez kullanmak istiyorum . Bu bloğun temel şablonumda birden fazla görünmesini istiyorum:

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

Ve sonra uzatın:

# 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 bloğun yalnızca bir kez görünmesini istediği için bir istisna alacağım:

/ Konumunda TemplateSyntaxError

"başlık" adlı "blok" etiketi birden fazla görünüyor

Hızlı ve kirli çözüm blok çoğaltarak olacağını başlığı içine TITLE1 ve TITLE2 :

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

Ancak bu, KURU ilkesine aykırıdır. Çok sayıda kalıtsal şablonum olduğu için ve ayrıca cehenneme gitmek istemediğim için çok zor olurdu ;-)

Bu problemde herhangi bir hile veya çözüm var mı? Tüm kodu kopyalamadan aynı bloğu şablonumda nasıl tekrar edebilirim?


1
bu sorudaki çözüme de bakın stackoverflow.com/q/1178743/168034
phunehehe

2
Özellikle phunehehe'nin bağlantı verdiği soruya verilen bu cevaba bakın .
Tobu

Yanıtlar:


69

Bağlam işlemcisinin kullanımının bu durumda aşırı bir beceri olduğunu düşünüyorum. Bunu kolayca yapabilirsiniz:

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

ve sonra:

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

ve benzeri ... DRY uyumlu görünüyor.


1
Bunu yarın deneyebilirim - şablonlarda biraz tekrarın nasıl kaydedileceğini merak ediyordum ve bu iyi bir yaklaşım gibi görünüyor. Teşekkürler.
thebiglife

1
Bu yaklaşım mükemmel. Base.html'mi base.html ve superbase.html'ye böldüm, bu nedenle, paylaşılan şablonlarınıza standart bir başlık işaretlemesi (h1 gibi) eklemek isterseniz de bu işe yarar. Sayfalar yine de başlık bloğunun içeriğini geçersiz kılabilir ve her iki konumda da güncellenir.
SystemParadox

2
Bu, metni ikiden fazla kullanmaya izin vermiyor, değil mi?
Dennis Golomazov

1
Denis Golomazov: Hayır. Bu durumda makro eklentiyi kullanmak daha iyidir (aşağıya bakın).
dqd

1
Bunun tam tersi de uygulanabilir: h1bloğun içindeki içeriği tanımlayan title. Ya da bir blok tanımlar kısmını arasında title.
Mikael Lindlöf

83

Django şablon makroları eklentisini kullanın:

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

veya

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

django> = 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>

ve

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

django <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>

ve

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

2
Bu fantastik! Bu, şablonları django döngüleri ve ajax veri döngüleri ile paylaşırken kazandığım sorunları gerçekten temizleyebilir.
Gliserin

1
Güzel çözüm. Ancak, "use_macro" dur. "usemacro" yanlış.
Ramtin

Varsayılan olarak kesinlikle Django'da yerleşik olmalıdır.
zepp.lee

19

Muhtemelen aslında bir blok kullanmak istemiyorsunuz, bunun yerine sadece bir değişken kullanmak istiyorsunuz:

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

Daha sonra başlığı bağlam aracılığıyla ayarlarsınız.


17
Muhtemelen Kuru. Ancak, görünüm içinde başlığı ayarlamak istemezsiniz; ama şablonlarda.
Lakshman Prasad

6
Başlıklar şablonlar içinden ayarlanmalıdır, bağlam tarafından sağlanmamalıdır, bu "başlık" değişkenini tanımlamanın bir yolunu bulmanız gerekir, aksi takdirde bu iyi bir çözüm değildir.
Guillaume Esquevin

Django yönetici şablonlarının yaptığı şey budur ({{title}} için), ancak bir kaldırmada başlığı tanımlamak sakıncalıdır.
Tobu

13

Aynı şeyi kendim yapmaya çalışırken keşfettiğim bir yol:

# 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 %}

Maalesef fazladan bir dosya gerektirir, ancak başlığı görünümden geçirmenizi gerektirmez.


Sonunda, yeni bir dosya gerektirmeyen ve genel olarak tam olarak ne ifade etmek istediğimi ifade etmeme izin veren {% macro%} çözümüne karar verdim.
Roman Starkov

basit ve verimli. @ dqd'nin cevabından farklı olarak, blokların iç içe geçmesine gerek yoktur, örneğin facebook og etiketleri için çok kullanışlıdır, diğer head öznitelikleriyle aynı içeriğe sahip olabilir. upvote!
benzkji

2
Mükemmel cevap. Bu, @ dqd'nin cevabından bile daha KURU görünüyor çünkü tabanı miras alan her şablonda <h1> etiketini tekrarlamak zorunda değilsiniz. Bu kabul edilen cevap olabilir.
Anupam

Mükemmel! Bunu, bir tablonun alt satırını en üstte tekrarlamak istediğim daha karmaşık senaryolarda kullandım. Ve <tr>sıra oldukça karmaşıktı.
caram


5

Burada bazı tartışmalar var: http://code.djangoproject.com/ticket/4529 Açıkçası django çekirdek ekibi bu bileti reddetti çünkü bunun yaygın kullanılan bir senaryo olmadığını düşünüyorlar, ancak ben katılmıyorum.

tekrar bloğu bunun için basit ve temiz bir uygulamadır: https://github.com/SmileyChris/django-repeatblock

şablon makroları bir diğeridir, ancak yazar dikkatlice test edilmediğini belirtti: http://www.djangosnippets.org/snippets/363/

Tekrar blok kullandım.


4
Orijinal django-tekrar blok deposu silinmiş gibi görünüyor. Bunun en iyi çatalı github.com/phretor/django-repeatblock gibi görünüyor ; Ben de buldum github.com/ydm/django-sameas bir 'wontfix' Django yama gerektirmez.
natevw

4

Bununla karşılaşan herkes için bir güncelleme olarak, yukarıda bahsedilen pasajı aldım ve onu bir şablon etiket kitaplığına dönüştürdüm, django-makrolar, makroları daha güçlü hale getiriyor ve ayrıca açıkça tekrarlanan bir blok modeli uyguluyor: django-makrolar .


4

İşte yukarıdakine benzer hafif bir çözüm do_setve do_getşablon etiketi cevabı. Django, tüm şablon bağlamını bir global değişken tanımlamanıza izin veren bir etikete geçirmenize izin verir.

base.html:

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

sayfa.html:

{% extends "base.html" %}

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

özel etiket (burada fikir var: https://stackoverflow.com/a/33564990/2747924 ):

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

Ayrıca {% load %}, özel etiketlerinizi de unutmayın veya bunları şablon seçenekleri yerleşik listesine ekleyin, böylece bunları her şablona yüklemeniz gerekmez. Bu yaklaşımın tek sınırlaması, {% define %}bir blok etiketi içinden çağrılması gerekliliğidir, çünkü alt şablonlar yalnızca ana etiketlerle eşleşen blok etiketlerini oluşturur. Bunun bir yolu olup olmadığından emin değilim. Ayrıca, defineaçıkça kullanmaya çalışmadan önce aramanın geldiğinden emin olun .


3

Van Gale'in önerisine dayanarak, templatetags.py dosyanıza aşağıdakileri ekleyerek alma ve ayarlama etiketleri oluşturabilirsiniz:

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)

Ardından bir şablonda değerleri ayarlayın {% set foo %}put data here{% endset %}ve bunları {% get foo %}başka bir şablondan alın .


Bence bu en zarif çözüm. Teşekkürler Kieran ve Van Gale!
Robert Lacroix

Bu oldukça şık, ancak tüm düğümleri Set etiketinde oluşturmak daha da iyi olabilir, aksi takdirde Get tarafından defalarca oluşturulurlar. İyi bir fikir olabilecek nedenler düşünebilirim (aynı depolanmış bloğu bir sayfadaki farklı blokların içinde işlemek), ama sadece onu işaret edeceğimi düşündüm.
acjay

3

Ben de şablon dosyalarımda tekrarlanan bir {% block%} ihtiyacı ile karşılaştım. Sorun şu ki, Django koşullu her iki durumda da Django {% block%} kullanılmasını istiyorum ve {% block%} geçerli dosyayı genişletebilecek sonraki dosyalar tarafından üzerine yazılabilir olmasını istiyorum. (Yani bu durumda, istediğim şey kesinlikle bir değişkenden çok bir blok, çünkü onu teknik olarak yeniden kullanmıyorum, sadece bir koşulun her iki ucunda da görünüyor.

Sorun:

Aşağıdaki Django şablon kodu bir Şablon Sözdizimi Hatası ile sonuçlanacaktır, ancak bunun bir koşulda yeniden kullanılması için geçerli bir "istek" olduğunu düşünüyorum (IE, Django ayrıştırıcısı neden sözdizimini BOTH uçlarında doğruluyor? bir koşullu, yalnızca GERÇEK koşulunu doğrulaması gerekmez mi?)

# 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 %}

Çözüm:

Koşullu olarak bir {% blok%} birden fazla eklemek için bir {% include%} kullanabilirsiniz. Bu benim için çalıştı çünkü Django sözdizimi denetleyicisi yalnızca GERÇEK {% include%} öğesini içeriyor. Aşağıdaki sonuca bakın:

# 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

İşleri kuru tutmak için bu cevabı kullanıyorum .

{% extends "base.html" %}

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

1

Bunun için iki kolay çözüm var.

En kolayı, başlığınızı bir bağlam değişkenine yerleştirmektir. Görünümünüzde bağlam değişkenini ayarlarsınız.

Genel görünümler gibi bir şey kullanıyorsanız ve resimler, kediler vb. İçin bir views.py'ye sahip değilseniz, o zaman bağlamda bir değişken ayarlayan özel bir şablon etiketinin yoluna gidebilirsiniz .

Bu rotaya gitmek, aşağıdakilere benzer bir şey yapmanızı sağlar:

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

Ardından base.html dosyanızda:

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

AncakAny 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

Seçilen yanıt, her ikisine de aynı değeri vermek için alt şablonda bir etiketi diğerinin içine sarmak için kolay bir geçici çözüm anlamına gelir. Bunu sosyal görseller için kullanıyorum.

Alt şablon:

{% 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 %}
...

Sonra ebeveynde 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

Gelen dal böyle yapabilirsiniz:

# 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
Bu Django ile ilgili bir sorudur.
François Constant
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.