Django — как получить содержимое тега {% block %} из шаблона

#python #regex #django #django-templates

#python #регулярное выражение #django #django-шаблоны

Вопрос:

Я зашел так далеко:

 >>> some_template = get_template_from_string(
...     load_template_source(
...         'some_template.html',
...         settings.TEMPLATE_DIRS))
... 
>>> blocks = some_template.nodelist.get_nodes_by_type(BlockNode)
>>> blocks[0]
<Block Node: another_block. Contents: [<Text Node: 'nThis one is really cool'>, <Block Node: sub_block. Contents: [<Text Node: 'nI'm a sub-block.nt'>]>, <Text Node: 'n'>]>
>>> # Right there is when I realized this wasn't going to be fun.
  

Видите ли, содержимое блока содержится в block.nodelist , в отличие от простого текста. Если у меня есть шаблон:

 {% extends "base.html" %}

{% block some_block %}
Some value
{% endblock %}

{% block other_block %}
Other Value
    {% sub_block %}Sub block value{% endblock %}
{% endblock %}
  

Я хочу иметь возможность сделать это:

 >>> get_block_source('other_block')
'nOther Valuen    {% sub_block %}Sub block value{% endblock %}n'
>>> get_block_source('sub_block')
'Sub block value'
  

Если внутренние компоненты Django не предоставляют достаточно ресурсов, чтобы найти способ сделать это, я согласен с использованием регулярного выражения / серии регулярных выражений, но я не понимаю, как это было бы возможно только с регулярным выражением, учитывая, что у вас могут быть вложенные {% block... теги.

Комментарии:

1. Мы делаем это, потому что часто есть лучший способ. Многие разработчики выбирают решение, заходят на полпути и застревают, а затем просто спрашивают, как решить проблему прямо перед ними, вместо того, чтобы спрашивать, как решить исходную проблему.

2. @orokusaki: Ах, возможно, вы неправильно его истолковали (или нет, трудно сказать). Обратите внимание, что если вы прочитаете его вопрос буквально, он просто попросит у вас больше информации о более серьезной проблеме: «Почему вы хотите это сделать?» Но в культурном плане мы привыкли интерпретировать этот вопрос, заданный так кратко, как «Вы ошибаетесь». Это большая проблема при использовании подобных онлайн-форумов.

Ответ №1:

Похоже, вы усердно работаете против зерна Django. Поместите содержимое во включаемый файл, затем {% include %} в свой блок, а также прочитайте файл напрямую. Если бы вы могли рассказать нам больше о том, чего вы пытаетесь достичь, вероятно, есть лучший способ сделать это.

Ответ №2:

Решение, которое я создал:

 import re


BLOCK_RE = re.compile(r'{%s*blocks*(w )s*%}')
NAMED_BLOCK_RE = r'{%%s*blocks*%ss*%%}'  # Accepts string formatting
ENDBLOCK_RE = re.compile(r'{%s*endblocks*(?:w s*)?%}')


def get_block_source(template_source, block_name):
    """
    Given a template's source code, and the name of a defined block tag,
    returns the source inside the block tag.
    """
    # Find the open block for the given name
    match = re.search(NAMED_BLOCK_RE % (block_name,), template_source)
    if match is None:
        raise ValueError(u'Template block {n} not found'.format(n=block_name))
    end = inner_start = start = match.end()
    end_width = 0
    while True:
        # Set ``end`` current end to just out side the previous end block
        end  = end_width
        # Find the next end block
        match = re.search(ENDBLOCK_RE, template_source[end:])
        # Set ``end`` to just inside the next end block
        end  = match.start()
        # Get the width of the end block, in case of another iteration
        end_width = match.end() - match.start()
        # Search for any open blocks between any previously found open blocks,
        # and the current ``end``
        nested = re.search(BLOCK_RE, template_source[inner_start:end])
        if nested is None:
            # Nothing found, so we have the correct end block
            break
        else:
            # Nested open block found, so set our nested search cursor to just
            # past the inner open block that was found, and continue iteration
            inner_start  = nested.end()
    # Return the value between our ``start`` and final ``end`` locations
    return template_source[start:end]