Search code examples
pythonflaskjinja2werkzeug

How to access variables within html template url_for


I'm building a Netflix like website for my Devops course. I made a Python list of dictionaries (Mockfilms) to define my films, and want to populate a database (Ratings) with reviews in preparation for sending data in the format :filmid: :userid: :rating: to a recommendation engine.

My index page is a list of film images with a link to a review form under each one. I want each review form to appear on a different url (/review/ID where ID is saved in mockfilms as oid). In order to do this I want to access mockfilms.oid, then pass it to the view function to make the url for the form. Once the form is complete I then want to add this ID to the Ratings database. Here is what I have so far:

Index:

{% extends "base.html" %}

{% block content %}
    <h1>Hello, {{ current_user.username }}! Welcome to our extensive video library:</h1>
    {% for film in mockfilms %}
    {% set ID = film.oid %}
    <div>
        <a href = {{ film.video }}>
            <img src = {{ film.image }} alt = "doh" style = "width:200px;height:200px;border:0;">
        </a>
    </div>
    <div>

        <a href={{ url_for('review', ID) }}"> ">Leave a review here!</a>
    {% endfor %}
{% endblock %}

Route:

@app.route('/review/<ID>', methods = ['GET', 'POST'])
@login_required
def review(ID):
    form = ReviewForm()
    if form.validate_on_submit():
        review = Ratings(User_id = current_user.id, Score_given = form.score.data, Film_id = ID)
        db.session.add(review)
        db.session.commit()
        flash('Thanks for your review')
        return redirect(url_for('index'))
    return render_template('review.html', title='Review Page', form=form)

The following error is what I get when I run it:

File "/home/jc/Desktop/Lokal/DevopsAssig/microblog/Kilfinnan/lib/python3.5/site-packages/werkzeug/routing.py", line 1768, in build raise BuildError(endpoint, values, method, self) werkzeug.routing.BuildError: Could not build url for endpoint 'review'. Did you forget to specify values ['ID']?

From this I assume that the issue is with the ID variable within this template. My searchings and learnings led me to believe that {% set %} in the index template would let me declare the ID variable and then use it in the dynamic.


Solution

  • Try this:

    {% block content %}
        <h1>
            Hello, {{ current_user.username }}! 
            Welcome to our extensive video library:
        </h1>
        {% for film in mockfilms %}
        <div>
            <a href="{{ film.video }}">
                <img src="{{ film.image }}" alt="doh" style="width:200px;height:200px;border:0;" />
            </a>
        </div>
        <div>
            <a href="{{ url_for('review', ID=film.oid) }}">
                Leave a review here!
            </a>
        </div>
        {% endfor %}
    {% endblock %}
    

    Ultimately your solution was quite close, but it is not necessary to use the Jinja set command when you need to pass the variable into url_for() function using the keyword for the parameter. You could still do it using {% set ID = film.oid %} but it would be a bit superfluous.