当前位置: 首页 > 面试题库 >

在Jinja 2中的包含文件顶部插入javascript

殳凯捷
2023-03-14
问题内容

在Jinja2中,我希望通过运行以下内容来使其看起来像应该的那样工作:

from jinja2 import Environment, FileSystemLoader
env = Environment(loader=FileSystemLoader('.'))
template = env.get_template('x.html')
print template.render()

本质上,目标是<head>使用aa{% call js() %} /* some js */ {% endcall %}宏将所有javascript合并到标签中。

x.html

<html>
<head>
  <script type="text/javascript>
  {% block head_js %}{% endblock %}
  </script>
  </head>
<body>
  {% include "y.html" %}
</body>
</html>

y.html

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

预期结果

当我通过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>

实际结果

实际结果并不令人鼓舞。我遇到了两种可能的照明错误,例如:

TypeError:宏“ js”不带关键字参数“ caller”

或者,当我尝试添加另一个基本宏时,例如

{% macro js2() -%}
{%- block head_js -%}
//     ... something
{%- endblock -%}
{%- endmacro %}

我得到以下异常

jinja2.exceptions.TemplateAssertionError:块’head_js’定义了两次

我觉得好像遇到了关于block标签优先于标签的设计问题macro(即宏似乎没有按照我期望的方式封装块标签)。

我想我的问题很简单:

  1. Jinja2可以做我想做的事吗?如果是这样,怎么办?

  2. 如果不是,是否有另一个基于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],
    )

这样可以很容易地将Javascript添加到模板的末尾…例如

<html>
<head></head>
<body>
    {% js %}
    some javascript {{ 3 + 5 }}
    {% endjs %}
    {% js %}
    more {{ 2 }}
    {% endjs %}

<script type="text/javascript">
{% js_content %}
</script>
</body>
</html>

运行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>

当然,这与希望的脚本不同,但至少可以方便地将其合并到一个位置。

但是,该解决方案并不完整,因为在其中有一个{% include "y.html" %}“ y.html”包含一条{% js %}语句的情况下,{% js_content %}gets在包含{% js %}语句之前被调用(即x.htmly.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 -->"

完成后,环境将包含jbc具有所有Javascript的变量。我可以通过插入string.Template


问题答案:

从我的评论:

如果您使用扩展而不是包含,则可以这样做。但是由于解析和渲染步骤之间完全分开,因此直到为时已晚,您才能更改父作用域的上下文。同样,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>

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


 类似资料:
  • 问题内容: 我正在为使用Jinja模板的服务器使用Flask微框架。 我有一个家长和孩子们的一些所谓的模板和,这些孩子有的模板是相当大的HTML文件,我想以某种分裂他们超过我的工作更好的洞察力。 我的脚本内容: The magic is in : 魔力在于child1.html: 而不是评论: 我有很多html文本,很难跟踪更改并且不犯一些错误,因此很难查找和纠正。 我只想加载而不是全部写入。 我

  • 问题内容: 我正在使用LiteIDE for Go。我的Go文件位于此处: 当我使用以下文件添加文件时: 导入“ ../Helper” 我收到此错误: 无法加载软件包:/Users/username/go/src/src/projectA/main.go:4:8:非本地软件包中的本地导入“ ../Helper” 有什么想法我做错了吗? 问题答案: 您通过导入路径导入软件包。对于位于中的packag

  • 我创建了一个spring boot应用程序,它读取一个excel文件,以便在前端显示数据,因此基本上它是持久数据的来源。我能够从eclipse正确地运行,但是当我创建一个spring boot jar并从命令行运行它时,它会失败,因为jar中没有包含文件。 我尝试了两个位置src/main/resources和/src/main/webapp/WEB-INF/external/,但在这两种情况下都

  • 问题内容: 我正在为JEE5 Web服务编写单元测试。Web服务的行为取决于文件中设置的属性。因此,我想将我分成一个恒定的部分和一个在两次测试之间更改的部分。 为了查看是否确实可行,我尝试查看是否可以拆分该属性。根据一些说明,我发现了以下几点: web.xml fragment.xml 但是,我在文件上收到验证错误: 必须为元素类型“ web-app”声明属性“ version”。[7] 必须为元

  • 问题内容: 我正在为Joomla编写模块,这时我真的需要能够使用Jfactory连接到数据库。通常一个人可以简单地使用,但是PHP错误告诉我不包含JFactory类。 所以现在我需要知道如何包括这个JFactory类 。我尝试了一些在互联网上发现的建议,但都没有成功。这是代码(独立运行时完​​美) 希望您能解决我的问题。您的帮助将不胜感激。 尝试1 但这也不起作用。 尝试2(成功) 现在一切正常。

  • 我有一个结构如下的maven项目: 我希望maven jar插件在构建jar文件时打包到数据库文件夹中。我尝试过包含这里概述的内容:https://maven.apache.org/plugins/maven-jar-plugin/examples/include-exclude.html,但它找不到目录“../database”(或../../database或../../../database

  • 问题内容: 我有一个包含几个JavaScript函数的JavaScript文件(extension ,不是)。 我想从一个JavaScript函数中仅包含几个PHP函数的PHP文件中调用其中一个PHP函数。 那可能吗? 我需要在文件中“包含” 包含PHP函数的文件吗? 我该怎么办? 例如,假设我有一个名为myLib.php的文件,其中包含一个带有两个参数(和)的函数。然后,我有一个包含名为的函数的

  • 问题内容: PEP8有一个关于将导入置于文件顶部的规则: 导入总是放在文件的顶部,紧随任何模块注释和文档字符串之后,以及模块全局变量和常量之前。 但是,在某些情况下,我可能想做些类似的事情: 在这种情况下,命令行实用程序会标记我的代码: E402模块级别导入不在文件顶部 通过修改达到PEP8的最佳方法是什么? 为什么 我有这段代码,因为我遵循的是《The Hitchhiker’s Guide to