Search code examples
pythonflaskjinja2

Is there a way to nest Flask variables (url_for) when passing to an HTML template? (Python)


I'm trying to template some of my common HTML elements by passing them as Flask variables, specifically my stylesheets and scripts. For further simplification and responsiveness I'm trying to use url_for to connect those.

In my app.py I have:

common_html = {
   'navbar': '''<nav class....>''',
   'scripts': '''<!-- D3 -->
        <script src="https://d3js.org/d3.v5.min.js"></script>
        <!-- Personal JS -->
        <script src="{{url_for('static', filename='javascript/myjs.js')}}"></script>'''
}

@app.route('/index')
def index():
   return render_template('index.html', common=common_html)

And in my HTML file:

...
<body>
   <!-- Nav --!>
   {{common['navbar']|safe}}
   <h1>Stuff</h1>
</body>
<!-- Scripts -->
{{common['scripts']|safe}}
</html>

In browser, my navbar code loads perfectly fine, however the script tag containing the url_for statement is not run properly. It appears as is <script src="{{url_for('static', filename='javascript/myjs.js')}}"></script> upon inspection. The script file is in the proper directory/filepath.

I've tried removing the {{}} double brackets and messing with the different quotations used to no avail. I have memory of this method working at some point previously, but can't say for certain.

Is there a practice or way to use url_for within a block of template code or is this poor practice? Any and all help would be appreciated!


Solution

  • I think the reason for this is that jinja doesn't render anything inside something that's already being rendered. So because you are passing the {{ url_for() }} inside a double brace, it will automatically escape anything in it. What you've basically done is put Jinja syntax in something that isn't evaluated by Jinja. So it actually looks like this:

    {{ "{{ url_for() }}" }}.

    Remember, Jinja will just put whatever's in the first double braces onto the page (after escaping), so it doesn't render the actual value of that {{url_for()}}. I would recommend using a base template which can then be inherited by your other pages.