Jinja保留包含或宏的缩进

时间:2012-05-30 17:47:23

标签: templates jinja2

我想知道在文件中添加包含或宏时是否有任何方法可以使用jinja缩进缩进。我想使用jinja生成代码文件。一个例子是

文件:class.html

class MyClass:
     def someOp():
         pass

     {% include "someOp.html" %}

文件:someOp.html

def someOp2():
    pass

模板的结果应为:

class MyClass:
     def someOp():
         pass

     def someOp2():
         pass

如果有任何方法让jinja在包含文件中每行的include标记之前添加缩进?或者有没有办法自定义jinja来做到这一点?

3 个答案:

答案 0 :(得分:20)

一种方法是将include包装在一个宏中,然后因为宏是一个函数,它的输出可以通过缩进过滤器传递:

class MyClass:
    def someOp():
        pass

    {% macro someop() %}{% include "someOp.html" %}{% endmacro %}
    {{ someop()|indent }}

默认情况下,'indent'缩进4个空格并且不缩进第一行,您可以使用例如'indent(8)'进一步缩进,有关详细信息,请参阅http://jinja.pocoo.org/docs/templates/#list-of-builtin-filters

如果您所包含的内容被定义为开始的宏,则不需要进一步的包装宏,您可以直接跳转到使用缩进过滤器。

答案 1 :(得分:1)

我一直在寻找Jinja2来实现相同的目的,并得出结论,目前无法将多行块缩进与原始Jinja语句对齐。

我在Jinja上发布了一个小型PR,以添加新的语法{%* ... %}{{* ... }}来实现此目的。有关详细信息,请参见PR:

https://github.com/pallets/jinja/pull/919

答案 2 :(得分:0)

如果Jinja提供了该设施,将会更加容易。看起来像设施was in the pipeline,但问题已解决(2019年11月20日),并且拉取请求尚未合并,一些技术问题仍需要解决。

以下是目前的解决方案。

auto_indent()检测主机模板中变量的缩进级别,然后将该缩进应用于一段文本:

import os
import itertools
import jinja2


def indent_lines(text_lines: list, indent: int):
    return [' ' * indent + line for line in text_lines]


def matching_line(s, substring):
    lineno = s[:s.index(substring)].count('\n')
    return s.splitlines()[lineno]


def is_space(c):
    return c == ' '


def indentation(line: str) -> int:
    initial_spaces = ''.join(itertools.takewhile(is_space, line))
    return len(initial_spaces)


def auto_indent(template: str, placeholder: str, content_to_indent: str):
    placeholder_line = matching_line(template, '{{ ' + placeholder + ' }}')
    indent_width = indentation(placeholder_line)
    lines = content_to_indent.splitlines()
    first_line = [lines[0]]  # first line uses placeholder indent-- no added indent
    rest = indent_lines(lines[1:], indent_width)
    return os.linesep.join(first_line + rest)

示例:

action_class = """\
class Actions:

    def __init__(self):
        pass

    def prequel(self):
        pass

    {{ methods }}

    def sequel(self):
        pass
"""

inserted_methods = """\
def create_branch():
    pass

def merge_branch():
    pass
"""


if __name__ == '__main__':
    indented_methods = auto_indent(action_class, 'methods', inserted_methods)
    print(jinja2.Template(action_class).render(methods=indented_methods))

示例输出:

>>> python indent.py
class Actions:

    def __init__(self):
        pass

    def prequel(self):
        pass

    def create_branch():
        pass

    def merge_branch():
        pass

    def sequel(self):
        pass

对于3.6之前的Python版本,请删除函数参数的类型提示。