Jinja2 for loop not processing variable data in html template

65 views Asked by At

I am new to building the web app with flask where I would like to show details in a modal popup. I am passing the class from my route to html template where I am trying to loop through the data twice to populate the table data first and then add modals for each row in the table.

Below is the code from my python route that is making the call to html template.

@bp.route('/search', methods=('GET', 'POST'))
def search(from_dt=datetime.today(),to_dt=datetime.today()):
    job_search = JobSearch()
    
    job_search.From_Date.default=from_dt
    job_search.To_Date.default=to_dt
    job_search.process()

    if request.method == 'POST':
        from_dt=request.form['From_Date']
        to_dt=request.form['To_Date']
        sqlcmd="select e.ID,j.job_name,e.start_date,e.end_date,e.status, l.exec_log \
            from jobs j, job_execs e, job_exec_logs l \
                Where j.id = e.job_id and e.id = l.job_exec_id and e.start_date between :SDT and :EDT"
        param={"SDT": from_dt, "EDT": to_dt}
        job_execs=db.session.execute(text(sqlcmd), param)
        #pdb.set_trace()
        return render_template('report/jobs.html', jobs=job_execs)
    return render_template('report/search.html', form=job_search)

Below is the html template that renders the webpage:

{% extends 'bootstrap/base.html' %}

{% block content %}
    <br><br><br>

    <h1>{% block title %} Job Executions {% endblock %}</h1>

        <TABLE class="table table-bordered table-hover">
            <thead>
                <tr>
                    <th class="text-center">Action</th>
                    <th class="text-center">Job Name</th>
                    <th class="text-center">Start</th>
                    <th class="text-center">End</th>
                    <th class="text-center">Execution Status</th>
                </tr>
            </thead>
            <tbody>
                {% for job in jobs %}
                    {% if job['status'] == 1 %}
                        <tr class="table-danger">
                    {% else %}
                        <tr class="table-success">
                    {% endif %}
                            <td><p><a href="{{ url_for('report.viewlog', id=job['ID']) }}"><img src="{{ url_for('static', filename='images/log.jpg') }}" alt="View job log" height="40px"></a></p></td> 
                            <td class="text-center">{{ job['job_name'] }} </td>
                            <td class="text-center">{{ job['start_date'] }} </td>
                            <td class="text-center">{{ job['end_date'] }} </td>
                            <td class="text-center">Error</td>
                            <td class="text-center">
                                <button type="button" class="btn btn-info btn-sm" data-toggle="modal" data-target="joblog{{ job['ID'] }}">View Log</button>
                            </td>
                        </tr>
                {% endfor %}
            </tbody>
        </Table>

    {% if jobs %}
        <!-- Job defined-->
    {% else %}
        <!-- Job undefined the for loop-->
    {% endif %}
    <!-- Before the for loop-->
    {% for j in jobs %}
        <!-- Modal -->
        <div class="modal fade" id="joblog{{ j['ID'] }}" role="dialog" aria-hidden="true">
            <div class="modal-dialog modal-lg" role="document">
                <!-- Modal content-->
                <div class="modal-content">
                    <div class="modal-header">
                        <button type="button" class="close" data-dismiss="modal">&times;</button>
                        <h4 class="modal-title">Job Log</h4>
                    </div>
                    <div class="modal-body">
                        <p><pre>{{ text }}{{ j['exec_log'] }}</pre></p>
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
                    </div>
            </div>
        </div>
    {% endfor %}
    <!-- After the for loop-->
{% endblock %}

When the page is loaded, I can see that it is processing the data only in the first loop while building the table. No output is being generated from the second for loop.

Below is what I see getting rendered.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <title> Job Executions Schdpy</title>
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
</head>
<body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
        <div class="container">
            <a href="/" class="navbar-brand">
                <img src="/static/images/home.jpg" alt="Jump to home page" height="40px">
            </a>
            <a href="#" onclick="window.history.back()">
                <img SRC="/static/images/back.jpg" alt="Go to previous page" height="40px">Back
            </a>
            <button class="navbar-toggler" type="button"
                data-toggle="collapse" data-target="#navbarResponsive"
                aria-controls="navbarResponsive" aria-expanded="false"
                aria-label="Toggle navigation">
                <span class="navbar-toggler-icon"></span>
            </button>
            <div class="collapse navbar-collapse" id="navbarResponsive">
                <ul class="navbar-nav ml-auto">
                    <li class="nav-item ">
                        <a href="/job/" class="nav-link">
                            <img src="/static/images/jobs.jpg" alt="List all jobs" height="40px"> Job List
                        </a>
                    </li>
                    <li class="nav-item ">
                        <a href="/job/create_job/" class="nav-link">
                            <img src="/static/images/new_job.jpg" alt="Add new job" height="40px"> New Job
                        </a>
                    </li>
                    <li class="nav-item ">
                        <a href="/report/" class="nav-link">
                            <img src="/static/images/report.jpg" alt="Reports" height="40px"> Job Reports
                        </a>
                    </li>
                    <li class="nav-item ">
                        <a href="/report/search" class="nav-link">
                            <img src="/static/images/search.jpg" alt="Search Job Executions" height="40px"> Job Execs
                        </a>
                    </li>                       
                </ul>
            </div>
        </div>
    </nav>
    <div class="container">
        <br><br><br><br><br>
    <h1> Job Executions </h1>
        <TABLE class="table table-bordered table-hover">
            <thead>
                <tr>
                    <th class="text-center">Action</th>
                    <th class="text-center">Job Name</th>
                    <th class="text-center">Start</th>
                    <th class="text-center">End</th>
                    <th class="text-center">Execution Status</th>
                </tr>
            </thead>
            <tbody>                  
                        <tr class="table-danger"> 
                            <td><p><a href="/report/3/viewlog"><img src="/static/images/log.jpg" alt="View job log" height="40px"></a></p></td> 
                            <td class="text-center">test job - edit with form </td>
                            <td class="text-center">2023-09-21 15:11:50 </td>
                            <td class="text-center">2023-09-21 15:11:50 </td>
                            <td class="text-center">Error</td>
                            <td class="text-center">
                                <button type="button" class="btn btn-info btn-sm" data-toggle="modal" data-target="joblog3">View Log</button>
                            </td>
                        </tr>
                        <tr class="table-success">
                    
                            <td><p><a href="/report/44/viewlog"><img src="/static/images/log.jpg" alt="View job log" height="40px"></a></p></td> 
                            <td class="text-center">test job - edit with form </td>
                            <td class="text-center">2023-10-09 19:57:22 </td>
                            <td class="text-center">2023-10-09 19:57:22 </td>
                            <td class="text-center">Error</td>
                            <td class="text-center">
                                <button type="button" class="btn btn-info btn-sm" data-toggle="modal" data-target="joblog44">View Log</button>
                            </td>
                        </tr>
            </tbody>
        </Table>
        <!-- Job defined-->
    <!-- Before the for loop-->
    <!-- After the for loop-->
    </div>
    <script src="https://code.jquery.com/jquery-3.4.1.min.js"
        integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo="
        crossorigin="anonymous">
    </script>
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/umd/popper.min.js" integrity="sha384-Q6E9RHvbIyZFJoft+2mJbHaEWldlvI9IOYy5n3zV9zzTtmI3UksdQRVvoxMfooAo" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js" integrity="sha384-wfSDF2E50Y2D1uUdj0O3uMBJnjuUD4Ih7YwaYd1iqfktj0Uod8GCExl3Og8ifwB6" crossorigin="anonymous"></script>
</body>
</html>

What am I missing that is preventing the second loop to generate the Modal? Your help is greatly appreciated.

I built this from the suggestion on Modal window in Jinja2 template. Flask solution.

To confirm if the variable was still valid after the first loop was done, I added an if condition to print an html code on the rendered page which I see if the condition is true. The generated page does has the html code that is within the if condition so I know that the variable is still valid.

<!-- Job defined-->
1

There are 1 answers

0
Gage Hilyard On BEST ANSWER

In Jinja iterators are consumed. Try saving it as a list before iterating over the first loop.

You can use it with this syntax:

{# Initialise myList with some values #}
{% set myList = [1,5,3,4,2] %}
{# add 5 to myList #} 
{% append 5 to myList %}
{# remove the second item from the list #} 
{% set temp = myList.pop(1) %}
{# find the index of the number 2 in myList #}
{% set myIndex = myList.index(2) %}
{# pop the number two from myList #} 
{% set temp = myList.pop(myIndex) %}
{# output the list and index of 1 #} 
{{ "values in my list:"}}
{{ myList }}
{% set indexOne = myList.index(1) %} 
{{ "</br> index of the number one:" }}
{{ indexOne }}