【问题标题】:jinja2 form include won't workjinja2 表单包含不起作用
【发布时间】:2014-01-04 06:57:21
【问题描述】:

我正在使用烧瓶和 jinja2 迈出第一步。我已经浏览了一些示例,但现在我尝试集成烧瓶安全性并卡住了一点。

我尝试使用登录表单构建一个模式,所以我放置了一个这样的 div:

<div class="modal">
<h3>Login</h3>
<form action="{{ url_for_security('login') }}" method="POST" name="login_user_form">
    {{ login_user_form.hidden_tag() }}
    {{ render_field_with_errors(login_user_form.email) }}
    {{ render_field_with_errors(login_user_form.password) }}
    {{ render_field_with_errors(login_user_form.remember) }}
    {{ render_field(login_user_form.next) }}
    {{ render_field(login_user_form.submit) }}
</form>

这是从flask-security提供的示例中获取的模板代码。现在我试着把它包起来

{% extends layout.html %}
{% block loginModal %} ... {% endblock %}

并尝试通过

在 layout.html 中调用它
{% block loginModal %}{% endblock %}

现在我学到的方法不是这样,因为内容被渲染并且 layout.html 只被调用。

现在我尝试通过 include 语句将该代码直接放入 layout.html 中,但由于这不起作用,我直接将其放入。

我也加了

{% from "security/_macros.html" import render_field_with_errors, render_field %}

在第一行,它们是由 flask-security 包提供的宏。但我得到的只是错误:

UndefinedError: 'login_user_form' is undefined (after a long traceback)

我完全被困在这里,在网站上阅读 jinja2 文档大约一个小时。我怎样才能让这个表格工作?

更新(抱歉,更新晚了):

我的 layout.html 实现了所有页面的基本布局

<!doctype html>
<html>
<head>
  <title>MyExample</title>
  <link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/style.css') }}">
  <link rel=stylesheet type=text/css href="{{ url_for('static', filename='css/gumby.css') }}">
</head>
<body>
  <div class=page>
    <nav id="navbar-main-nav" class="navbar">
      <div class="row">
      <a class="toggle" gumby-trigger="#navbar-main-nav #main-nav" href="#"><i class="icon-menu"></i></a>
      <h1 class="four columns logo"><a href="/">Logo</a></h1>
      <nav class="five columns pull_right">
        <ul id="main-nav">
          <li><a href="/link1/"><span>Link1 </span></a></li>
          <li><a href="/link2/"><span>Link2</span><i class="icon-cog" title="Customize"></i></a></li>
    {% if current_user.is_authenticated() %}
    <li>Hello {{ current_user.name }}</li>
    <li><a href="{{ url_for('security.logout') }}">Logout</a></li>
    {% else %}
    <li><a href="#" class="switch" gumby-trigger="#modal1">Open Modal</a></li>
    <li><a href="{{ url_for('security.register') }}">Register</a></li>
    {% endif %}
    </ul>
  </nav>
    </div>
  </nav>

  <div class="modal" id="modal1">
    <div class="content">
      <a class="close switch" gumby-trigger="|#modal1"><i class="icon-cancel" /></i></a>
        <div class="row">
          <div class="ten columns centered">
            <div class="row">
              <div class="five columns">
                {% block loginModal %}{% endblock %}
              </div>
              <div class="five columns">
                 <!-- register Form -->
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>

    {% block body %}{% endblock %}
  </div>
  <script src="{{ url_for('static', filename='js/libs/modernizr-2.6.2.min.js') }}"></script>
  <script src="{{ url_for('static', filename='js/libs/jquery-2.0.2.min.js') }}"></script>
  <script gumby-touch="js/libs/" src="{{ url_for('static', filename='js/libs/gumby.min.js') }}"></script>

</body>
</html>

我的登录.html

{% extends layout.html %}
{% block loginModal %}
{% from "security/_macros.html" import render_field_with_errors, render_field %}
{% include "security/_messages.html" %}

   <h3>Login</h3>
   <form action="{{ url_for_security('login') }}" method="POST" name="login_user_form">
      {{ login_user_form.hidden_tag() }}
      {{ render_field_with_errors(login_user_form.email) }}
      {{ render_field_with_errors(login_user_form.password) }}
      {{ render_field_with_errors(login_user_form.remember) }}
      {{ render_field(login_user_form.next) }}
      {{ render_field(login_user_form.submit) }}
  </form>
{% endblock %}

以一种抽象的方式,我想构建一个像小部件这样的东西,我可以在另一个模板中导入并使用它来实现一次这样的东西,比如登录表单。后来我希望能够实现列表,可以将其放置在每个页面的侧边栏中,而无需在每个页面上单独实现。我找到了Flask Plugable Views,但我还没有找到一个很好的例子来理解正确的用法。

更新 2:

这个(更新的)实现根本不呈现任何形式,没有任何错误。我想我可能误解了块的使用。

** 解决方案**

在 Mark 的帮助下,我发现模板上下文处理器作为一种变量注入非常有用。对于某些人来说可能很明显:flask-security 提供表单作为导入,因此我的代码现在看起来像这样:

from flask.ext.security import LoginForm, RegisterForm
...
@app.context_processor
def inject_userForms():
    return dict(login_user_form=LoginForm(), register_user_form=RegisterForm() )

我将表单直接添加到我的 layout.html 中,现在效果很好。根本不起作用的是包含块。如果我使用 blockception,它可以工作,在内容块中使用登录块。

【问题讨论】:

  • 你说的“现在我学到的不是方式,因为内容被渲染并且 layout.html 只被调用”是什么意思?就我而言,您提供的方式将是正确的做事方式。也许您可以提供您如何尝试使用此方法的完整来源?此外,您的表单 HTML 中似乎缺少一个结束 &lt;/div&gt; 元素,不确定是否是导致问题的原因。
  • 所以 layout.html(通常被命名为 base.html)构建了我的线框。并有一个 {% block body %}{% endblock %} 然后呈现内容。我也有一个 index.html 呈现身体。我用谷歌搜索了很多,发现几个条目说如果一个块应该呈现它必须在呈现的模板中,在这种情况下是 index.html 而不是 layout.html/base.html。我试着举一个更长的例子。
  • 我明白这一点,但我的意思是,我认为您在设置 layout.html 和使用 layout.html 的模板时可能存在一些错误。您说您是如何根据问题中提供的内容更改文件的,但是如果我们没有看到您修改的实际结果,我们不确定您是否确实正确地进行了修改。请修改问题以向我们提供模板的版本(layout.html 和子模板),然后是它输出的 HTML。最后,告诉我们您希望它输出什么。
  • 我已经用一个例子编辑了原始帖子。我期望输出的是 layout.html 中的登录表单,在每个页面上,模式都可以用于登录或注册。

标签: python html forms flask jinja2


【解决方案1】:

你的错误是:

UndefinedError: 'login_user_form' 未定义

这是来自模板,看起来像这样......

{% extends layout.html %}
{% block loginModal %}
{% from "security/_macros.html" import render_field_with_errors, render_field %}
{% include "security/_messages.html" %}

   <h3>Login</h3>
   <form action="{{ url_for_security('login') }}" method="POST" name="login_user_form">
      {{ login_user_form.hidden_tag() }}
      {{ render_field_with_errors(login_user_form.email) }}
      {{ render_field_with_errors(login_user_form.password) }}
      {{ render_field_with_errors(login_user_form.remember) }}
      {{ render_field(login_user_form.next) }}
      {{ render_field(login_user_form.submit) }}
  </form>
{% endblock %}

因此,您引用了 login_user_form,但 Jinja2 抱怨您实际上没有定义 login_user_form。您通常在尝试调用函数来呈现模板时定义它。

def my_view():
    # ...
    return render_template('login.html', login_user_form=login_user_form)

如果您没有将“login_user_form”作为参数传递给 render_template,您将收到错误消息。

如果您希望 login_user_form 在应用程序其他地方的模板上下文中定义(例如在 template context processor 中),请确保您的应用程序的该部分确实在工作。

【讨论】:

  • 当我读到这篇文章时,我发现我忘记了信息,在更新的示例中,表单根本没有呈现没有任何错误。我已经更新了我原来的帖子。
  • 再读一遍:你是对的,但是我在哪里可以为基本 html 实现这个视图。因为我从来没有直接调用它来由路由渲染,所以我不知道如何实现渲染的未路由实现。实际上这对我有很大帮助,因为它似乎是实现可重用小部件的关键信息。
  • 我还是不明白你的问题。归根结底,您可以将 Jinja 对 extendsblock 的使用视为将多个模板组合成一个大模板的简单方法。然后,它将使用模板上下文来找出像login_user_form 这样的东西。无论您尝试在layout.htmllogin.html 页面中使用login_user_formlogin_user_form 仍然需要在上下文中。您可以使用render_template 的参数或使用模板上下文处理器(正如我在答案中链接到的那样)来提供它。
  • 另外,在这个问题和你的 Flask 错误报告中,你讨论了 base.htmllayout.html。你确定你没有混淆它们吗?
  • 所以你是对的:我阅读了有关模板上下文处理器的链接文档。我还发现,flask-security 提供了登录表单等基本表单作为导入:from flask.ext.security LoginForm然后我可以在这样的上下文处理器中使用它@app.context_processor def inject_userForms(): return dict(login_user_form=LoginForm())
猜你喜欢
  • 2016-05-31
  • 2016-01-29
  • 2016-02-17
  • 1970-01-01
  • 2012-06-04
  • 1970-01-01
  • 1970-01-01
  • 2017-06-29
  • 2012-06-20
相关资源
最近更新 更多