Django - 如何从模板中获取{% block %}标签的内容

4 投票
2 回答
2211 浏览
提问于 2025-04-17 04:16

我已经做到这一步了:

>>> 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.\n\t'>]>, <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 Value\n    {% sub_block %}Sub block value{% endblock %}\n'
>>> get_block_source('sub_block')
'Sub block value'

如果Django内部的功能不够用来找到实现这个的方法,我也可以接受使用正则表达式或者一系列的正则表达式,但我觉得仅靠正则表达式是没办法做到的,因为你可能会有嵌套的 {% block... 标签。

2 个回答

2

看起来你在用Django的时候走了些弯路。你可以把内容放到一个单独的文件里,然后在你的代码块里用{% include %}来引入这个文件,同时也可以直接读取这个文件。如果你能告诉我们你想要实现什么,可能会有更好的方法来做到这一点。

0

我创建的解决方案:

import re


BLOCK_RE = re.compile(r'{%\s*block\s*(\w+)\s*%}')
NAMED_BLOCK_RE = r'{%%\s*block\s*%s\s*%%}'  # Accepts string formatting
ENDBLOCK_RE = re.compile(r'{%\s*endblock\s*(?:\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]

撰写回答