5.5. Variables in URLs#

In this section, we’ll explore how Flask allows us to create dynamic web pages by passing variables through URLs. This is useful when we want our web pages to display different content depending on the value passed in the URL.

5.5.1. Basic Example#

Let’s start with a simple example where we’ll use Flask to display a message that includes a variable from the URL.

from flask import Flask

app = Flask(__name__)

@app.route('/greet/<name>')
def greet(name):
    return "Hello, {}!".format(name)

app.run(debug=True, port=5000)

Explanation

  • Defining the route:

    • The @app.route('/greet/<name>') decorator tells Flask that when someone visits a URL that matches /greet/<name>, the greet() function should be executed.

    • <name> is a placeholder in the URL that acts as a variable. Whatever value the user types in place of <name> will be passed to the greet() function.

  • Route function:

    • The function greet(name) accepts name as a parameter. Flask automatically extracts the value from the URL and passes it to the function.

    • We return a simple message that includes the name variable, which will be displayed on the web page.

5.5.2. Review Page#

Now let’s take a look at how we can use this concept in our “Movie Reviews” website. We’ll create a page that shows all the information for a movie review based on its id. The id is passed as a variable in the URL.

For example, visiting http://127.0.0.1:5000/movie/2 would display the details of “Barbie.”

app.py#
 1from flask import Flask, render_template
 2from sqlalchemy import create_engine, text
 3
 4app = Flask(__name__)
 5
 6# Connect to the database
 7engine = create_engine('sqlite:///movies.db')
 8connection = engine.connect()
 9
10@app.route('/movie/<int:movie_id>')
11def movie_page(movie_id):
12    # Get the movie review by its ID
13    query = text("SELECT * FROM reviews WHERE id={}".format(movie_id))
14    result = connection.execute(query).fetchall()
15
16    if len(result) > 0:
17        # Take first (hopefully the only) result
18        movie = result[0]
19        return render_template('movie_page.html', movie=movie)
20    else:
21        return "Movie not found", 404
22
23app.run(debug=True, port=5000)
movie_page.html#
 1<!DOCTYPE html>
 2<html>
 3    <head>
 4        <title>{{ movie[1] }}</title>
 5    </head>
 6    <body>
 7        <p><a href="/">Home</a></p>
 8        <hr>
 9
10        <h1>{{  movie[1] }} ({{ movie[2] }})</h1>
11        <p><b>Genre:</b> {{ movie[3] }}</p>
12        <p><b>Review Date:</b> {{ movie[4] }}</p>
13        <p><b>Score:</b> {{ movie[5] }}/10</p>
14        <p><b>Review:</b> {{ movie[6] }}</p>
15    </body>
16</html>

Explanation

  • Defining the Route:

    • The @app.route('/movie/<int:movie_id>') decorator registers a route where movie_id is an integer variable that will be extracted from the URL.

    • When someone visits /movie/1, Flask will extract the value 1 and pass it to the movie_page() function as movie_id.

  • Function Logic:

    • Inside the movie_page() function, we use movie_reviews.get(movie_id) to retrieve the movie data that matches the given id. If a movie with that id exists, it returns the corresponding data. If not, it returns a 404 error with message "Movie not found".

  • Rendering the Template:

    • The render_template('movie_page.html', movie=movie) line uses Flask’s template engine to render an HTML page and pass the movie data to it.

5.5.3. Complete Example#

Project structure:

├── app.py
├── movies.db
└── templates
    └── index.html
    └── movie_page.html
app.py#
 1from flask import Flask, render_template
 2from sqlalchemy import create_engine, text
 3
 4app = Flask(__name__)
 5
 6# Connect to the database
 7engine = create_engine('sqlite:///movies.db')
 8
 9@app.route('/')
10def home():
11    # SQL query to select all movies
12    query = text("SELECT * FROM reviews")
13    result = engine.execute(query).fetchall()
14
15    # Render the template and pass the result
16    return render_template('index.html', movies=result)
17
18@app.route('/movie/<int:movie_id>')
19def movie_page(movie_id):
20    # Get the movie review by its ID
21    query = text("SELECT * FROM reviews WHERE id={}".format(movie_id))
22    result = connection.execute(query).fetchall()
23
24    if len(result) > 0:
25        # Take first (hopefully the only) result
26        movie = result[0]
27        return render_template('movie_page.html', movie=movie)
28    else:
29        return "Movie not found", 404
30
31app.run(debug=True, port=5000)
index.html#
 1<!DOCTYPE html>
 2<html lang="en">
 3    <head>
 4        <title>Movie Reviews</title>
 5    </head>
 6    <body>
 7        <h1>Movie Reviews</h1>
 8        <ul>
 9            {% for movie in movies %}
10                <li><a href="/movie/{{ movie[0]}}">{{ movie[1] }} ({{ movie[2] }}) - Score: {{ movie[5] }}</a></li>
11            {% endfor %}
12        </ul>
13    </body>
14</html>

Explanation:

  • For each movie, we link to the corresponding movie page

movie_page.html#
 1<!DOCTYPE html>
 2<html>
 3    <head>
 4        <title>{{ movie[1] }}</title>
 5    </head>
 6    <body>
 7        <h1>{{  movie[1] }} ({{ movie[2] }})</h1>
 8        <p><strong>Genre:</strong> {{ movie[3] }}</p>
 9        <p><strong>Review Date:</strong> {{ movie[4] }}</p>
10        <p><strong>Score:</strong> {{ movie[5] }}/10</p>
11        <p><strong>Review:</strong> {{ movie[6] }}</p>
12    </body>
13</html>