-1

I will preface by saying this is my first time working with flask & HTML to build a web app, so I may be using the wrong terminology in some places, apologies in advance.

I have used these two previous questions as reference for what i'm doing:

Flask render a word cloud

Passing a matplotlib figure to HTML (flask)

I am working a web app that allows a user to input a movie, and a wordcloud is returned.

The user starts on /search, where they input a movie name, I then redirect to /search_results where a list of movies with similar names are shown, the user selects the right film and submits. This part of the journey is all working fine, from here I take the movie name, I then apply a function I have built in python that creates a wordcloud based on this film name (in my code below this is what the function wordcloud_generator(1,session['search_value']) is doing in the fig route). The output of the wordcloud_generator() function is:

...
img = BytesIO()
wordcloud.to_image().save(img, 'PNG')
img.seek(0)  
return img

I want to save this image to a route "/fig/<wordcloud_img>" and then be able to call it in the src of an img tag in the route "/images/<wordcloud_img>".

When running through this I get the error of at the point that I submit the movie name from /search_results and redirect to 'images'. Error: werkzeug.routing.BuildError: Could not build url for endpoint 'images'. Did you forget to specify values ['wordcloud_img']?

After this if I navigate manually to "localhost:5000/fig/wordcloud_img" then my function seems to run and the image is shown, and then if I manually navigate to "localhost:5000/images/wordcloud_img" the image is properly surfaced in the html.

It seems like I am doing this in the wrong order somehow and the function isn't running/generating the image before I try to access it on the /images source.

Routes

def search():
    if request.method == 'POST':
        movie_search = request.form['search_text']
        session['returned_movies'], session['search_links'] = search_function(search_term = movie_search)
        return redirect(url_for('search_result'))
    return render_template('search.html',title='Search')

@app.route("/search_result", methods=['GET', 'POST'])
def search_result():
    if request.method == 'POST':
        movie = request.form['movie']
        session['search_value'] = session['search_links'][session['returned_movies'].index(movie)]
        return redirect(url_for('images'))
    return render_template('search_results.html',title='Search Results')

@app.route("/images/<wordcloud_img>")
def images(wordcloud_img):
    return render_template("wordcloud.html")

@app.route("/fig/<wordcloud_img>")
def fig(wordcloud_img):
    img = wordcloud_generator(1,session['search_value'])
    return send_file(img, mimetype='image/png')

wordcloud.html

{% extends "layout.html" %}
{% block content %}
<div>
    {% if session['search_value'] %}   
    <p>Searching for a movie: {{ session['search_value'] }}</p>
    {% else %}
    <p>Oops, no movie selected </p>
    {% endif %}  
    <body>
        <img src="{{ url_for('fig', wordcloud_img = 'wordcloud_img') }}" alt="Image Placeholder" height="100">
    </body>
</div>
{% endblock content %}
cigien
  • 57,834
  • 11
  • 73
  • 112

1 Answers1

0

The problem is that you are not passing the image to the 'images' function that displays the template with the image. In your 'search_result' function, you will need to pass the wordcloud_image to the 'images' function like so:

return redirect(url_for('images'), wordcloud_img=your_image)

(replacing your_image with the actual image variable)

In your images route, you would then need to pass this received image to the template:

return render_template("wordcloud.html", wordcloud_img=wordcloud_img)

Then in your template, you can use this wordcloud_img variable like this:

<img src="{{ url_for('fig', wordcloud_img=wordcloud_img) }}" alt="Image Placeholder" height="100">
Patrick Yoder
  • 1,065
  • 4
  • 14
  • 19