Dynamic nav-bar elements – passed from Flask to Jinja – inherited layout template

Question:

Environment: Python 3.6, Flask 1.02, Jinja2

Objective:

  • Create a dynamic menu in layout.html (which is extended by content.html)
  • yet the url_for of the dynamic element is frequently requires a parameter to be passed

Issue statement:
How can I pass the parameters for url_for in Jinja template when rendering the template?

I feel like I would need the syntax of str().format in Jinja..

I tried to:

1. pass each part as a separate value:

menus = [{'url': 'func_name', 'menu_title': 'title', 'param': 'param_name', 'param_val': 'param_value'}] 
return render_template('content1.html', menus=menus]

in jinja I tried to call it like: (I also tried it without the plus and double-quotes)

{{ url_for(func_name), param_name+ "=" + param_val }}

During rendering it gives error of
url_for() takes 1 positional argument but 2 were given

2. tried to use the {% set var_name: passed_variable %}

Built on 1st version of menus defined on server side, I tried to set the variables within Jinja, but also failed.

menus = [{'url': 'func_name', 'menu_title': 'title', 'param': 'param_name', 'param_val': 'param_value'}] 
    return render_template('content1.html', menus=menus]

Jinja

{% for menu in menus %}
{% set url = menu.get('url') %}
{% set param = menu.get('param') %}
{% set value = menu.get('param_val') %}
{% url_for(url, param + "=" + value %}

Yet it also didn’t work.
It feels like if I give a param for the url_for syntax (not a hard-wired string) I cannot add the parameters.

3. tried to pass whole content of url_for as a string:

menus={'url_string': " 'func_name', param_name=param_value"}

yet it fails again as url_for syntacs put the whole between apostrophes, which I wouldn’t need at the end.

Some references I scanned through.
Flask context-processor

It could work if I would create another template of each nav-bar for each content page – yet with that move i could simply move the navbar into the content page. However that seems dull. Stack Overflow topic

Thus question:
How can I pass the

param_id=paramval['id']

for the url_for syntax during rendering

{{ url_for('edit_question', param_id=paramval['id']) }}

The code/structure stg like below:
layout.html

<html>
<body>
    {% for menu in menus %}
        {% for key, value in menu.items() %}
            <a href="{{ url_for(value) }}" >
                {{ key }}
            </a>
        {% endfor %}
    {% endfor %}
{% block content %}

{% endblock %}
</body>
</html>

content1.html

{% extends 'layout.html' %}
{% block content %}
 content
{% endblock %}

content2.html

{% extends 'layout.html' %}
{% block content %}
 content
{% endblock %}

app.py

@app.route('/')
def index():
    menus = [{'menu_title1': 'menu_func_name1'}]
    return render_template('content1.html', menus=menus)

@app.route('/menu_details/<int:menu_nr>')
def show_details_of_menu(menu_nr):
    menus = [{'menu_title3': 'menu_func_name3', 'menu_param_name': 'menu_param_value'} 
    return render_template('content2.html', menus=menus)

sorry for the Wall of text..

Asked By: Neophyte

||

Answers:

sigh.. after hours I just found how to construct the syntax. I hope it will help others!

During rendering:

menus = [{'url': 'func_name', 'menu_title': 'title', 'parameters': {'param1': param1_value}}]
return render_template('context.html', menus=menus]

In Jinja, I adjusted the syntax to manage cases where no parameters are needed:

            {% for menu in menus %}
                {% if menu.get('parameters').items()|length > 0 %}
                    <a href="{{ url_for(menu.get('url'), **menu.get('parameters')) }}">
                        {{ menu.get('menu_title') }}
                    </a>
                {% else %}
                    <a href="{{ url_for(menu.get('url')) }}">
                        {{ menu.get('menu_title') }}
                    </a>
                {% endif %}
            {% endfor %}

Answered By: Neophyte
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.