Search code examples
pythonhtmlflaskjinja2

Passing a dictionary from pythonFlask to Jinja2, error keeps telling me variable is undefined


Overall my goal is to dynamically update a table in html with data from a dictionary passed through flask into a jinja loop.

In trying to populate an html table with data from a dictionary created in pythonFlask through passing it in a jinja2 loop, I continually get the error: "jinja2.exceptions.UndefinedError: 'results' is undefined".

I've properly defined my dictionary in Flask, the return/render statement, and the jinja2 loop but for some reason it fails with an internal server error, claiming it is undefined.

My current code is as follows...

jinja2/html:

{% extends "hw12_home.html" %}
{% block header %} Word counter! {% endblock %}
{% block paragraph %} Type or paste any text in to count. {% endblock %}

{% block body %}

<form action="/wordCount" method="POST">
    <textarea name = "wordCount_text" rows = "20" cols = "125"></textarea> <br>
    <input type ="Submit" value = "Count Words!">
</form>

<table id = "word_table">
    <tr>
        <th> Word: </th>
        <th> Count: </th>
    </tr>

{% for key, value in results.items() %}
            <tr> <td> {{ key }} </td> <td> {{ value }} </td></tr>
{% endfor %}
    

</table>
{% endblock %}

pythonFlask:

@app.route('/wordCount' , methods= ['GET', 'POST'])
def wordCount ():
    
    if request.method == 'POST':
        
        wordCount_text = request.form['wordCount_text']
        wordCount_split = wordCount_text.split(' ')
        
        results = {}
        uniqueWords = []
        
        for word in wordCount_split:
            if word != '' and word not in uniqueWords:
                uniqueWords.append(word)
                results[word] = ""
        
        for word in uniqueWords:
            count = 0
            for word_2 in wordCount_split:
                if word == word_2:
                    count += 1
            results[word] = str(count)
       
        return render_template('word_count.html', results=results)
        
    return render_template('word_count.html')

I've tried the following in the jinja loop, .iteritems() , .itervalues()

I've looked at multiple solutions on stack and even web resources that show syntax that mimics my setup , but for some reason 'results' is still being shown as undefined.

I know my dictionary is setup with the results I expect thanks to this test print statement: enter image description here

I've also tried passing the dictionary in the return/render statement like this and that didn't work either: enter image description here

I'm expecting a table that looks like this... enter image description here

Originally I attempted it with two lists and a nested jinja2 for loop, but the nested loop would complete its iterations before breaking out and continuing to include the data from the first loop, resulting in a table that looked like this:

enter image description here

my jinja/html code for this attempt looked like this:

{% for i in uniqueWords %}
    <tr> <td> {{ i }} </td>
        {% for j in countList %}
            <td> {{ j }} </td> </tr>
        {% endfor %} 
    {% endfor %}

Overall, I can't figure out why i'm being told results is undefined.

Thanks for any suggestions in advance.


Solution

  • Your wordCount() view has two return statements. One when the method is POST and another one when its a GET. When its a GET you are not passing anything to the variable results which is why you are getting results is undefined. There are two ways you can solve this:

    • You could pass an empty dictionary to the template when the method is GET so is not undefined.
    @app.route('/wordCount' , methods= ['GET', 'POST'])
    def wordCount ():
      if request.method == 'POST':
        #...
        return render_template('word_count.html', results=results)
    
      return render_template('word_count.html', results={})
    
    • or in jinja2 you can check first whether a variable is defined or not. {% if variable is defined %} so in your template word_count.html the loop should be wrapped by the if condition.
    {% if results is defined %}
    {% for key, value in results.items() %}
        <tr> <td> {{ key }} </td> <td> {{ value }} </td></tr>
    {% endfor %}
    {% endif %}