1

I'm trying to re-use my flask-security login form in a couple of different places, so I defined it as a macro like this:

{% macro loginForm(inForm) %}
    <form class="form-signin" action="{{ url_for_security('login') }}" method="POST" name="loginForm">
        {{ inForm.hidden_tag() }}

        {{ renderFieldWithErrors(inForm.email, class="form-control top", placeholder="Login ID", required=True, autofocus=True) }}
        {{ renderFieldWithErrors(inForm.password, class="form-control bottom", placeholder="Password", required=True) }}

        <div class="checkbox">
            <label>
                {{ inForm.remember() }} Remember me
            </label>
        </div>
        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>

        <p style="margin-top: 1em;"><a href="{{ url_for_security('forgot_password') }}">Trouble Logging In?</a></p>
    </form>
{% endmacro %}

Unfortunately, url_for_security is undefined in this context. If I change it to url_for, it works fine, but then it says hidden_tag doesn't exist. It seems the macro doesn't have the same set of things defined as the calling context. Can this be corrected? Thanks.

Rick
  • 3,298
  • 3
  • 29
  • 47
  • how about use `url_for("security.login")`? – stamaimer Mar 28 '17 at 12:36
  • I finally figured out how `url_for()` and friends works, and was able to do what I needed. I guess my real question is how to import symbols into macros, but I managed to do everything I needed with whatever's available by default. – Rick Mar 28 '17 at 19:50
  • Can you post your method as the answer of your question? – stamaimer Mar 29 '17 at 02:14
  • It's not really an answer to the original question, which has to do with importing symbols into macros. Maybe that "just works" like in any other jinja template? I haven't tried. – Rick Mar 29 '17 at 23:34

1 Answers1

0

Macros by default are imported with context in Jinja. From the documentation:

By default, included templates are passed the current context and imported templates are not. The reason for this is that imports, unlike includes, are cached; as imports are often used just as a module that holds macros.

and:

This behavior can be changed explicitly: by adding with context or without context to the import/include directive, the current context can be passed to the template and caching is disabled automatically.

I encountered this problem myself, and solved it by changing the way the macros were imported in my pages:

{% import "security/_components.html" as components with context %}

Keep in mind that this will disable the caching mechanism, so depending on what the macros are doing you might experience a performance hit (although I don't have enough experience to extend on this point).

If you want to retain the caching, then the solution @stamaimer provided in his comment works without problems: url_for("security.login") instead of url_for_security("login") inside the macro.

fresbeeplayer
  • 93
  • 1
  • 5