Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

During build: string concatenation in url_for() fails when data comes from render_template() #121

Open
LokiWijnen opened this issue Oct 14, 2021 · 2 comments

Comments

@LokiWijnen
Copy link

When running Flask normally, everything described below works absolutely fine.

When running a build in Frozen-Flask however, I run into the issue where my dynamically built route string won't allow me to concatenate a variable (containing a string) with a string for use in a url_for() function within Jinja2. But only when the variable data is originating from Python such as render_template().

routes.py

@app.route('/some-route/')
def some_route():
    return render_template('my_template.html', foo='bar')

base.html

{% import "includes.html" as includes %}
{{ includes.my_macro(foo) }}

includes.html

# The following does NOT work
{% macro my_macro(foo) %}
    <a href="{{ url_for('index_' ~ foo) }}">Link text</a>
{% endmacro %}

Although the above runs fine in Flask, when I do a build with Frozen-Flask I get the following error:

werkzeug.routing.BuildError: Could not build url for endpoint 'index_'. Did you mean...

As you can see, the value of foo (or the string value bar) is missing. It should have been index_bar.

So I tried this instead:

# This also does NOT work
{% macro my_macro(foo) %}
    {% set route = 'index_' ~ foo %}
    <a href="{{ url_for(route) }}">Link text</a>
{% endmacro %}

The above produces the exact same error.

So I tried this to try to better understand the problem:

# This works correctly
{% macro my_macro(foo) %}
    {% set route = 'index_' ~ 'bar' %}
    <a href="{{ url_for(route) }}">Link text</a>
{% endmacro %}

So I further tried this:

# This also works correctly
{% macro my_macro(foo) %}
    {% set foo2 = 'bar' %}
    {% set route = 'index_' ~ foo2 %}
    <a href="{{ url_for(route) }}">Link text</a>
{% endmacro %}

So basically, I can create a dynamic route string for use by url_for() but only when the variable data doesn't come from the Flask routes file (such as my routes.py), only if the variable is created within Jinja2.

@TomHall2020
Copy link

Your routes.py file in the example only defines some_route. I'm trying to understand your setup here, do you actually have multiple routes with endpoints index_bar, index_other etc? If so you may want to create a true dynamic route as follows:

@app.route('/somewhere/<foo>')
def somewhere(foo):
    return render_template('my_template.html', foo=foo)

then in your templates you can access these via url_for as url_for(somewhere, foo='bar') and skip out the macro and string concatenation in the template.

@LokiWijnen
Copy link
Author

I am aware that I can do this:

url_for(somewhere, foo='bar')

But this isn't the problem that I am trying to solve.


The issue (ignoring jinja macros for this explanation) is that url_for will not accept a concatenate a string with a variable originating in Flask when running a Build, but it works fine when running Flask normally.

So, for example if the value coming from Flask is language = 'en' like this:

return render_template('my_template.html', language='en')

Then in Jinja, I can't do this:

{{ url_for('index_' ~ language) }}

To get it to work, I have to do something like this where I create a Jinja variable:

{% set jinja_language = 'de' if language == 'de' else 'en' %}

{{ url_for('index_' ~ jinja_language) }}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants