Flask: Handling GET and POST Requests
Flask, a lightweight Python web framework, provides robust support for handling HTTP requests, including GET and POST methods, which are essential for building dynamic web applications. These methods enable interaction between clients (e.g., browsers) and servers, making them critical for data-driven applications like dashboards or machine learning (ML) interfaces using Pandas. This guide covers Flask handling GET and POST requests, including setup, processing, integration with Jinja2 templates, best practices, and practical examples, with a focus on data-driven use cases.
01. Overview of GET and POST Requests
HTTP requests are used to communicate between clients and servers. Flask routes handle these requests to perform actions like retrieving data (GET) or submitting data (POST).
- GET Request: Retrieves data from the server (e.g., loading a page or fetching query parameters).
- POST Request: Sends data to the server for processing (e.g., form submissions).
- Key Components:
request
object, route decorators, and form handling. - Use Cases: Displaying Pandas DataFrames, submitting ML model inputs, or filtering dashboard data.
1.1 Flask’s request
Object
The request
object, imported from flask
, provides access to request data:
request.method
: The HTTP method ('GET'
or'POST'
).request.args
: Query parameters for GET requests.request.form
: Form data for POST requests.
02. Handling GET Requests
GET requests are used to retrieve data, often via URL query parameters or direct page access. Flask routes handle GET requests by default.
2.1 Basic GET Request
Example: Simple GET Request
File: app.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def home():
return render_template('index.html')
if __name__ == '__main__':
app.run(debug=True)
File: templates/index.html
<!DOCTYPE html>
<html>
<head>
<title>Home</title>
</head>
<body>
<h1>Welcome to the Flask App</h1>
<p>This is a GET request.</p>
</body>
</html>
Output (http://127.0.0.1:5000/):
A simple page with the welcome message.
Explanation:
@app.route('/')
: Handles GET requests to the root URL by default.render_template
: Renders the Jinja2 template.
2.2 GET with Query Parameters
Query parameters (e.g., ?name=Alice
) are accessed via request.args
.
Example: GET with Query Parameters
File: app.py
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/greet')
def greet():
name = request.args.get('name', 'Guest')
return render_template('greet.html', name=name)
if __name__ == '__main__':
app.run(debug=True)
File: templates/greet.html
<!DOCTYPE html>
<html>
<head>
<title>Greet</title>
</head>
<body>
<h1>Hello, {{ name | title }}!</h1>
<p>This is a GET request with query parameters.</p>
</body>
</html>
Output (http://127.0.0.1:5000/greet?name=Alice):
A page displaying Hello, Alice!
.
Output (http://127.0.0.1:5000/greet):
A page displaying Hello, Guest!
.
Explanation:
request.args.get('name', 'Guest')
: Retrieves thename
parameter, defaulting toGuest
.| title
: Formats the name in the template.
03. Handling POST Requests
POST requests are used to submit data, typically via HTML forms. Flask routes must explicitly allow POST methods using the methods
parameter in @app.route
.
3.1 Basic POST Request
Example: Simple Form Submission
File: app.py
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/submit', methods=['GET', 'POST'])
def submit():
if request.method == 'POST':
name = request.form.get('name', 'Guest')
return render_template('result.html', name=name)
return render_template('form.html')
if __name__ == '__main__':
app.run(debug=True)
File: templates/form.html
<!DOCTYPE html>
<html>
<head>
<title>Form</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Submit Your Name</h1>
<form method="post">
<div class="form-group">
<label>Name:</label>
<input type="text" name="name" class="form-control">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
File: templates/result.html
<!DOCTYPE html>
<html>
<head>
<title>Result</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Hello, {{ name | title }}!</h1>
<a href="{{ url_for('submit') }}" class="btn btn-secondary">Back</a>
</div>
</body>
</html>
Output (/submit):
- GET: Displays a Bootstrap-styled form.
- POST (name=Alice): Renders a page with
Hello, Alice!
and a back button.
Explanation:
methods=['GET', 'POST']
: Allows both GET and POST requests.request.form.get('name', 'Guest')
: Retrieves form data, with a default.form method="post"
: Submits data to the same route.
3.2 Handling File Uploads with POST
POST requests can handle file uploads, useful for ML model inputs or data files.
Example: File Upload
File: app.py
from flask import Flask, render_template, request
import os
app = Flask(__name__)
UPLOAD_FOLDER = 'uploads'
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
if 'file' not in request.files:
return render_template('upload.html', error='No file selected')
file = request.files['file']
if file.filename == '':
return render_template('upload.html', error='No file selected')
file.save(os.path.join(app.config['UPLOAD_FOLDER'], file.filename))
return render_template('upload.html', message=f'File {file.filename} uploaded')
return render_template('upload.html')
if __name__ == '__main__':
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
app.run(debug=True)
File: templates/upload.html
<!DOCTYPE html>
<html>
<head>
<title>Upload</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<div class="container">
<h1>Upload File</h1>
{% if error %}
<p class="text-danger">{{ error }}</p>
{% endif %}
{% if message %}
<p class="text-success">{{ message }}</p>
{% endif %}
<form method="post" enctype="multipart/form-data">
<div class="form-group">
<label>File:</label>
<input type="file" name="file" class="form-control">
</div>
<button type="submit" class="btn btn-primary">Upload</button>
</form>
</div>
</body>
</html>
Output (/upload):
- GET: Displays a file upload form.
- POST (valid file): Saves the file to
uploads/
and shows a success message. - POST (no file): Shows an error message.
Explanation:
enctype="multipart/form-data"
: Required for file uploads.request.files['file']
: Accesses the uploaded file.file.save
: Saves the file to the specified folder.
04. GET and POST in Data-Driven Applications
GET and POST requests are critical for data-driven Flask applications, enabling data retrieval (e.g., dashboard displays) and submission (e.g., ML model inputs).
Example: ML Prediction Dashboard
File: app.py
from flask import Flask, render_template, request
import pandas as pd
app = Flask(__name__)
@app.template_filter('probability')
def probability_filter(value):
try:
return f"{float(value) * 100:.1f}%"
except (ValueError, TypeError):
return value
@app.route('/')
def home():
return render_template('home.html')
@app.route('/dashboard', methods=['GET', 'POST'])
def dashboard():
df = pd.DataFrame({
'Name': ['Alice', 'Bob', 'Charlie'],
'Age': [25, 30, 35],
'Salary': [50000, 60000, 55000]
})
prediction = None
if request.method == 'POST':
prediction = float(request.form.get('prediction', 0.5))
return render_template('dashboard.html', data=df.to_dict(orient='records'), prediction=prediction)
if __name__ == '__main__':
app.run(debug=True)
File: templates/base.html
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}ML App{% endblock %}</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
</head>
<body>
<nav class="navbar navbar-light bg-light">
<a class="navbar-brand" href="{{ url_for('home') }}">ML App</a>
</nav>
<div class="container mt-3">
{% block content %}{% endblock %}
</div>
</body>
</html>
File: templates/home.html
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
<h1>Welcome</h1>
<p>Visit the <a href="{{ url_for('dashboard') }}">Dashboard</a> to view data and make predictions.</p>
{% endblock %}
File: templates/dashboard.html
{% extends 'base.html' %}
{% block title %}Dashboard{% endblock %}
{% block content %}
<h1>ML Prediction Dashboard</h1>
<table class="table table-striped">
<thead>
<tr>
<th>Name</th>
<th>Age</th>
<th>Salary</th>
</tr>
</thead>
<tbody>
{% for row in data %}
<tr>
<td>{{ row.Name | title }}</td>
<td>{{ row.Age }}</td>
<td>${{ row.Salary | float | round(2) }}</td>
</tr>
{% endfor %}
</tbody>
</table>
<form method="post">
<div class="form-group">
<label>Prediction Input (0-1):</label>
<input type="number" step="0.01" name="prediction" class="form-control" required>
</div>
<button type="submit" class="btn btn-primary">Predict</button>
</form>
{% if prediction is not none %}
<p>Prediction Probability: {{ prediction | probability }}</p>
{% endif %}
{% endblock %}
Output (/dashboard):
- GET: Displays a table with Pandas data and a prediction form.
- POST (prediction=0.75): Shows the table and
Prediction Probability: 75.0%
.
Explanation:
GET
: Renders the dashboard with Pandas data.POST
: Processes the prediction input and displays the result.| probability
: Custom filter formats the prediction.
05. Best Practices for Handling GET and POST Requests
5.1 Recommended Practices
- Use
request.args.get
andrequest.form.get
: Provide defaults to handle missing data gracefully. - Validate Input: Check and sanitize user inputs to prevent errors or security issues.
- Specify Methods: Explicitly define
methods=['GET', 'POST']
for routes handling both. - Use CSRF Protection: For POST requests, use Flask-WTF or similar to prevent cross-site request forgery.
- Provide Feedback: Display success/error messages in templates after POST requests.
- Use
url_for
: Generate URLs dynamically in forms and links.
5.2 Security Considerations
- Sanitize Inputs: Use libraries like
bleach
to clean user inputs. - Escape Outputs: Rely on Jinja2’s default escaping or
| escape
for user data. - File Uploads: Validate file types and sizes, and store files securely.
Example: Insecure Input Handling
File: app.py
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/comment', methods=['POST'])
def comment():
comment = request.form['comment']
return render_template('comment.html', comment=comment)
if __name__ == '__main__':
app.run(debug=True)
File: templates/comment.html
<!DOCTYPE html>
<html>
<head><title>Comment</title></head>
<body>
<p>{{ comment | safe }}</p> <!-- Insecure -->
</body>
</html>
Input: comment=<script>alert('XSS')</script>
Output: Executes the script (XSS vulnerability).
Correct:
<!DOCTYPE html>
<html>
<head><title>Comment</title></head>
<body>
<p>{{ comment | escape }}</p> <!-- Safe -->
</body>
</html>
Output: Displays <script>alert('XSS')</script>
safely.
Explanation:
- Insecure -
| safe
with user input risks XSS. - Correct -
| escape
ensures safe rendering.
5.3 Practices to Avoid
- Avoid Unvalidated Inputs: Always validate and sanitize user data.
- Avoid Hardcoding URLs: Use
url_for
in forms and redirects. - Avoid Large File Uploads: Set size limits and validate file types.
06. Conclusion
Handling GET and POST requests in Flask is fundamental for building interactive, data-driven web applications, particularly for dashboards and ML interfaces. Key takeaways:
- GET requests retrieve data, often with query parameters, using
request.args
. - POST requests submit data, such as forms or files, using
request.form
orrequest.files
. - Integrate with Pandas for data display and form submissions for ML inputs.
- Follow best practices like input validation, CSRF protection, and secure output rendering.
By mastering GET and POST request handling, you can create robust, secure, and user-friendly Flask applications that effectively manage data interactions in dynamic contexts!
Comments
Post a Comment