Bri*_*unt 10 python templates mako genshi jinja2
在Jinja2中,我希望通过运行以下内容来实现它的运行:
from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('x.html')
print template.render()
Run Code Online (Sandbox Code Playgroud)
本质上,目标是<head>
通过使用{% call js() %} /* some js */ {% endcall %}
宏来将所有javascript合并到标签中.
<html>
<head>
<script type="text/javascript>
{% block head_js %}{% endblock %}
</script>
</head>
<body>
{% include "y.html" %}
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
{% macro js() -%}
// extend head_js
{%- block head_js -%}
{{ super() }}
try { {{ caller() }} } catch (e) {
my.log.error(e.name + ": " + e.message);
}
{%- endblock -%}
{%- endmacro %}
Some ... <div id="abc">text</div> ...
{% call js() %}
// jquery parlance:
$(function () {
$("#abc").css("color", "red");
});
{% endcall %}
Run Code Online (Sandbox Code Playgroud)
当我通过jinja2运行X.html时,我希望结果如下:
<html>
<head>
<script type="text/javascript>
try { {{ $("#abc").css("color", "red"); }} } catch (e) {
usf.log.error(e.name + ": " + e.message);
}
</script>
</head>
<body>
Some ... <div id="abc">text</div> ...
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
实际结果并不令人鼓舞.我得到了几种可能有启发性的错误,例如:
TypeError:宏'js'不带关键字参数'caller'
或者,当我尝试添加另一个基础宏如
{% macro js2() -%}
{%- block head_js -%}
// ... something
{%- endblock -%}
{%- endmacro %}
Run Code Online (Sandbox Code Playgroud)
我得到以下异常
jinja2.exceptions.TemplateAssertionError:块'head_js'定义了两次
我觉得好像我遇到了关于block
标签在macro
标签上的优先级的设计问题(即宏似乎没有以我期望的方式封装块标签).
我想我的问题很简单:
Jinja2可以做我正在尝试的事吗?如果是这样,怎么样?
如果没有,是否有另一个基于Python的模板引擎支持这种模式(例如mako,genshi等),这在Google App Engine中可以正常工作
感谢您的阅读 - 感谢您的投入.
布赖恩
我正在尝试编写扩展来解决此问题.我在那里 - 使用以下代码:
from jinja2 import nodes, Environment, FileSystemLoader
from jinja2.ext import Extension
class JavascriptBuilderExtension(Extension):
tags = set(['js', 'js_content'])
def __init__(self, environment):
super(JavascriptBuilderExtension, self).__init__(environment)
environment.extend(
javascript_builder_content = [],
)
def parse(self, parser):
"""Parse tokens """
tag = parser.stream.next()
return getattr(self, "_%s" % str(tag))(parser, tag)
def _js_content(self, parser, tag):
""" Return the output """
content_list = self.environment.javascript_builder_content
node = nodes.Output(lineno=tag.lineno)
node.nodes = []
for o in content_list:
print "\nAppending node: %s" % str(o)
node.nodes.extend(o[0].nodes)
print "Returning node: %s \n" % node
return node
def _js(self, parser, tag):
body = parser.parse_statements(['name:endjs'], drop_needle=True)
print "Adding: %s" % str(body)
self.environment.javascript_builder_content.append(body)
return nodes.Const('<!-- Slurped Javascript -->')
env = Environment(
loader = FileSystemLoader('.'),
extensions = [JavascriptBuilderExtension],
)
Run Code Online (Sandbox Code Playgroud)
这使得将Javascript添加到模板的末尾变得简单......例如
<html>
<head></head>
<body>
{% js %}
some javascript {{ 3 + 5 }}
{% endjs %}
{% js %}
more {{ 2 }}
{% endjs %}
<script type="text/javascript">
{% js_content %}
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
运行env.get_template('x.html').render()
将产生一些有启发性的评论和预期的输出:
<html>
<head>
<script type="text/javascript>
</script>
</head>
<body>
<!-- Slurped Javascript -->
<!-- Slurped Javascript -->
<script type="text/javascript">
some javascript 8
more 2
</script>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
当然,这与脚本中的脚本不一样,但至少它可以方便地合并到一个地方.
但是,解决方案并不完整,因为当你有一个{% include "y.html" %}
"y.html"包含一个{% js %}
语句时,{% js_content %}
在include {% js %}
语句之前调用gets (即x.html
在y.html
开始之前完全解析).
我还需要,但还没有,插入具有静态javascript的常量节点,try/catch
我表示我想要在那里.这不是问题.
我很高兴能取得进步,我很感激投入.
我打开了相关的问题:Jinja2编译扩展后包含
解
class JavascriptBuilderExtension(Extension):
tags = set(['js'])
def __init__(self, environment):
super(JavascriptBuilderExtension, self).__init__(environment)
environment.extend(jbc = "",)
def parse(self, parser):
"""Parse tokens """
tag = parser.stream.next()
body = parser.parse_statements(['name:endjs'], drop_needle=True)
return nodes.CallBlock(
self.call_method('_jbc', [], [], None, None),
[], [], body
).set_lineno(tag.lineno)
def _jbc(self, caller=None):
self.environment.jbc += "\ntry { %s } catch (e) { ; };" % caller()
return "<!-- Slurped -->"
Run Code Online (Sandbox Code Playgroud)
完成后,环境将包含一个包含jbc
所有Javascript 的变量.我可以插入这个,例如,string.Template
.
从我的评论:
如果您使用extend而不是include,则可以执行此操作.但是由于解析和渲染步骤之间的完全分离,您将无法更改父范围的上下文,直到它为时已晚.此外,Jinja上下文应该是不可变的.
例:
base.html文件
<html>
<head>
{% block head %}
<title>{% block title %}This is the main template{% endblock %}</title>
<script type="text/javascript">
{% block head_js %}
$(function () {
$("#abc").css("color", "red");
});
{% endblock %}
</script>
{% endblock head_js %}
</head>
<body>
{% block body %}
<h1>{% block body_title %}This is the main template{% endblock body_title %}</h1>
{% endblock body %}
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
some_page.html
{% block title %}This is some page{% endblock title %}
{% block head_js %}
{{ super() }}
try { {{ caller() }} } catch (e) {
my.log.error(e.name + ": " + e.message);
} // jquery parlance:
{% endblock head_js %}
Run Code Online (Sandbox Code Playgroud)