6.6. Forms (GET)#

HTML forms are essential for collecting user input, and the GET method is one of the key ways to send that data to a server. In this section, we’ll explore how GET forms work, how Flask handles GET requests, and how we can use query strings to filter data. We’ll also build a movie filtering page as an example.

6.6.1. Forms over HTTP#

When a form is submitted, the browser sends the form data to the server using HTTP. The two most common methods are:

  • GET: Sends data as part of the URL, typically used for retrieving data.

  • POST: Sends data in the body of the request, used for submitting data such as forms or file uploads.

We will focus on the GET method on this page. Forms involving POST are described on Forms (POST).

6.6.2. HTML Forms#

A HTML form that uses is a structure that allows users to submit data through the URL of a web page. For forms using GET the data is encoded in the URL itself, making them ideal for:

  • Search queries

  • Filters for content (e.g., filtering movies by genre)

  • Bookmarkable URLs (since the data is visible in the URL, users can save and share the link)

Everyday examples include search bars on websites (e.g., Google) and filters on e-commerce sites (e.g., filtering by price or category).

6.6.3. Query Strings#

When using the GET, the data is sent in the URL as a query string. Query strings consist of key-value pairs appended to the URL, and they follow this format:

http://example.com/search?key1=value1&key2=value2
  • Key: The name of the input field in the form.

  • Value: The value entered by the user.

6.6.4. Example Form#

Here’s an example of a form using GET where users can search by name:

<!DOCTYPE html>
<html>
<head>
    <title>Search Form</title>
</head>
<body>
    <h1>Search</h1>
    <form action="/search" method="GET">
        <label for="query">Enter your search:</label>
        <input type="text" id="term" name="term"><br><br>

        <input type="submit" value="Search">
    </form>
</body>
</html>

Explanation

  • <form action="/search" method="GET"> creates a form that submits data to the /search URL using the GET method. This means the input will appear in the URL after submission.

  • <input type="text" id="term" name="term"> creates a text input for the user’s search term. The name attribute will become the key in the query string.

  • <input type="submit" value="Search"> creates a button to submit the form data.

When the form is submitted with “Flask” as the search term, the URL will look like this:

6.6.5. Handling Query Strings#

Here’s how you can handle the query string data in Flask:

from flask import Flask, request

app = Flask(__name__)

@app.route('/search', methods=['GET'])
def search():
    # Access the query string data
    term = request.args.get('term', '')

    if term:
        return f"You searched for: {term}"
    else:
        return "No search term provided."

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

Explanation

  • The /search route listens for GET requests.

  • request.args.get('term', '') is used to retrieve the value of the term parameter from the URL. The request.args dictionary contains all the query string data. If no value is provided, it defaults to an empty string ('').

  • The server returns a message that displays what the user searched for.

6.6.6. Example: Filter Reviews#

Let’s create an example where we filter the movies in the “Movie Reviews” database by attributes like genre or review score. The user will select filters using a form, and the results will be displayed based on the selected filters.

Project structure:

├── app.py
├── movies.db
└── templates/
    └── search.html
    └── filter.html
app.py#
 1from flask import Flask, request, 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('/search')
10def filter_movies():
11    return render_template('search.html')
12
13@app.route('/filter', methods=['GET'])
14def filter_movies():
15    # Get filter parameters from the query string
16    genre = request.args.get('genre', '')
17    score = request.args.get('score', '')
18
19    conditions = []
20    if genre:
21        conditions.append("genre={}".format(genre))
22    if score:
23        conditions.append("score>={}".format(score))
24
25    condition_str = " and ".join(conditions)
26
27    # Get the movie review that match the conditions
28    query = text("SELECT * FROM reviews WHERE {}".format(condition_str))
29    result = connection.execute(query).fetchall()
30
31    return render_template('movie_list.html', movies=filtered_movies)
32
33app.run(debug=True, port=5000)

Explanation

  • <form action="/filter" method="GET"> creates a form that submits the selected filters to the /filter URL using the GET method.

  • <select id="genre" name="genre"> creates a dropdown list of genres. The name="genre" attribute ensures that the selected genre is sent as a query string parameter.

  • <input type="number" id="score" name="score"> allows users to specify a minimum review score. The name=”score” attribute ensures this value is sent as a query string parameter.

  • <input type="submit" value="Filter Movies"> sends the selected filter options to the server when clicked.

When the form is submitted with “Action” as the genre and “8” as the minimum score, the URL will look like this:

search.html#
 1<!DOCTYPE html>
 2<html>
 3    <head>
 4        <title>Search Reviews</title>
 5    </head>
 6    <body>
 7        <h1>Filter Movies</h1>
 8        <form action="/filter" method="GET">
 9            <label for="genre">Genre:</label>
10            <select id="genre" name="genre">
11                <option value="">Any</option>
12                <option value="Action">Action</option>
13                <option value="Comedy">Comedy</option>
14                <option value="Drama">Drama</option>
15                <option value="Animation">Animation</option>
16            </select><br><br>
17
18            <label for="score">Minimum Review Score:</label>
19            <input type="number" id="score" name="score" min="1" max="10"><br><br>
20
21            <input type="submit" value="Filter Movies">
22        </form>
23    </body>
24</html>

Explanation

  • The /filter route listens for GET requests with query string parameters for filtering movies.

  • request.args.get('genre', '') and request.args.get('score', '') retrieve the values of the genre and score parameters from the URL. If no value is provided, they default to an empty string ('').

  • The reviews` table is queried to retrieve reviews that match the conditions.

  • The filtered list of movies is passed to the movie_list.html template, which displays the movies.

filter.html#
 1<!DOCTYPE html>
 2<html>
 3    <head>
 4        <title>Movie List</title>
 5    </head>
 6    <body>
 7        <h1>Filtered Movies</h1>
 8        <ul>
 9            {% for movie in movies %}
10                <li>{{ movie[1] }} ({{ movie[2] }}) - Score: {{ movie[5] }}</li>
11            {% endfor %}
12        </ul>
13    </body>
14</html>

Explanation

  • This template loops through the filtered movies and displays each movie’s title, genre, and review score in a list.

6.6.7. Glossary#

Query String#

TODO