Back to Blog
Python

Python Flask Query Parameters and Forms

python flask query path parameters and forms: Learn how to access query parameters and form data in Flask routes, handle missing values, validate input, and choose bet...

FlaskQuery ParametersForm DataHTTP RequestsWeb Development
Illustration of a Flask route receiving query parameters and form data, with a URL containing a question mark and a form icon.

When building a Flask application, you often need to read data sent by the client. That data arrives either as query parameters in the URL or as form fields in the request body. Understanding how to access both is essential for handling python flask query path parameters and forms correctly. This article explains the difference, shows how to read each type, and covers common pitfalls.

Accessing Query Parameters with request.args

Query parameters are the key-value pairs that appear after the ? in a URL, such as /search?q=flask&page=2. In Flask, the request.args object gives you access to these values as an immutable MultiDict. You can retrieve a single value with get():

from flask import Flask, request app = Flask(__name__) @app.route('/search') def search(): query = request.args.get('q') page = request.args.get('page', default=1, type=int) return f"Searching for {query!r} on page {page}"

The get() method accepts a default value and a type conversion function. If the parameter is missing, the default is returned. If the type conversion fails, the default is also used. This keeps the handler concise without manual error checking.

For multiple values with the same name, use getlist():

@app.route('/filter') def filter_items(): tags = request.args.getlist('tag') return f"Filtering by tags: {tags}"

This is useful for checkboxes or repeated query parameters like /filter?tag=python&tag=flask.

Reading Form Data with request.form

Form data is sent in the request body, typically with POST or PUT. In Flask, request.form provides access to parsed form fields as a MultiDict. A minimal form handler looks like this:

from flask import request, render_template_string @app.route('/signup', methods=['GET', 'POST']) def signup(): if request.method == 'POST': username = request.form.get('username') email = request.form.get('email') return f"Registered {username} with {email}" return render_template_string(''' <form method="post"> <input name="username" type="text"> <input name="email" type="email"> <button type="submit">Sign up</button> </form> ''')

The same get() and getlist() methods work on request.form. Note that request.form only contains URL-encoded or multipart form data. JSON payloads are accessed via request.get_json() instead.

Handling Both Query and Form Data in One Route

A route can receive both query parameters and form data simultaneously. For example, a form might submit to a URL that includes a tracking token in the query string:

@app.route('/submit', methods=['POST']) def submit(): token = request.args.get('token') value = request.form.get('value') return f"Token: {token}, Value: {value}"

This works because request.args and request.form are independent. The query string is parsed from the URL, while the form body is parsed from the request payload. You can also access the raw request body with request.data if needed, but that is rarely necessary for standard forms.

Dealing with Missing or Invalid Parameters

A common mistake is assuming a parameter always exists. If you call request.args['key'] and the key is absent, Flask raises a 400 Bad Request error. Use get() to avoid this:

name = request.args.get('name') if name is None: return "Missing name parameter", 400

For form data, the same rule applies. If a required field is missing, you should return a meaningful error message. A simple pattern is to check for emptiness and return a 400 response:

@app.route('/login', methods=['POST']) def login(): username = request.form.get('username') password = request.form.get('password') if not username or not password: return "Username and password are required", 400 # authenticate...

When using type conversion, remember that invalid values fall back to the default. If you need to distinguish between a missing parameter and an invalid one, inspect the raw string first:

raw_page = request.args.get('page') if raw_page is not None: try: page = int(raw_page) except ValueError: return "Invalid page number", 400 else: page = 1

Validating and Converting Input Values

Beyond simple type conversion, you often need to validate that values meet certain criteria. For example, an email address should contain an @, or a date should be in ISO format. Flask does not enforce validation rules; you must implement them yourself or use a library like WTForms. For small applications, manual checks are sufficient:

from datetime import datetime @app.route('/events') def events(): start = request.args.get('start') if start: try: start_date = datetime.fromisoformat(start) except ValueError: return "Invalid start date format", 400 else: start_date = None # ...

If you need to accept a list of values, getlist() returns a list, but each element is still a string. Convert each element explicitly if needed.

Security Considerations for Form Handling

When accepting form data, you must protect against Cross-Site Request Forgery (CSRF). Flask does not include CSRF protection by default. For production applications, use an extension like Flask-WTF to generate and validate CSRF tokens. Without CSRF protection, an attacker could trick a user into submitting a form that changes their data.

Another concern is data size. By default, Flask does not limit the request body size. A malicious client could send a huge form, consuming memory. You can set MAX_CONTENT_LENGTH on the app configuration:

app.config['MAX_CONTENT_LENGTH'] = 1024 * 1024 # 1 MB

If the limit is exceeded, Flask returns a 413 Request Entity Too Large response.

Also, never trust user input directly in SQL queries or HTML output. Use parameterized queries and escape output with Jinja2's autoescaping, which is enabled by default in templates.

When to Use Query Parameters vs Form Data

The choice between query parameters and form data depends on the action being performed. Query parameters are appropriate for read-only requests, such as search filters or pagination. They are visible in the URL, which makes them shareable and bookmarkable. Form data is better for state-changing operations like login, registration, or creating resources, because the data is in the request body and not exposed in the URL.

A practical guideline is to use GET with query parameters for idempotent operations that do not modify state, and POST with form data for actions that have side effects. This aligns with HTTP semantics and improves cacheability and security. For example, a search page should use GET /search?q=..., while a comment submission should use POST /comments with the comment text in the form body.

Combining both is sometimes necessary, such as when a form needs to preserve a return URL in the query string. In that case, read the query parameter for the redirect target and the form fields for the actual submission data. Keep in mind that sensitive data should never be placed in query parameters because it appears in server logs and browser history.

python flask query path parameters and forms: Practical Usag | RYUSLOG DEV