Quiz 2

Flask Forms — Handling User Input

899 words
4 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Flask Forms — Handling User Input ## 🎯 Learning Objectives - Handle GET and POST requests in Flask - Access form data from `request.form` - Validate form data and show error messages - Use flash messages for user feedback - Use WTForms for form validation ## 1. Handling Form Submissions ### 1.1 A Simple Contact F...

Flask Forms — Handling User Input

🎯 Learning Objectives

  • Handle GET and POST requests in Flask
  • Access form data from request.form
  • Validate form data and show error messages
  • Use flash messages for user feedback
  • Use WTForms for form validation

1. Handling Form Submissions

1.1 A Simple Contact Form

python
# app.py
from flask import Flask, render_template, request
app = Flask(__name__)
@app.route('/contact', methods=['GET', 'POST'])
def contact():
    if request.method == 'POST':
        name = request.form['name']
        email = request.form['email']
        message = request.form['message']
        # Process the data (save to database, send email, etc.)
        print(f"Received from {name}: {message}")
        return render_template('thankyou.html', name=name)
    return render_template('contact.html')
html
<!-- templates/contact.html -->
<form method="POST" action="/contact">
    <label for="name">Name:</label>
    <input type="text" id="name" name="name" required>
    <label for="email">Email:</label>
    <input type="email" id="email" name="email" required>
    <label for="message">Message:</label>
    <textarea id="message" name="message" rows="4" required></textarea>
    <button type="submit">Send</button>
</form>

1.2 GET vs POST

  • GET: Data in URL (/search?q=flask). Use for searches, read-only queries.
  • POST: Data in request body. Use for mutations (create, update, delete).
python
@app.route('/search')
def search():
    query = request.args.get('q', '')  # GET parameters via request.args
    results = search_database(query)
    return render_template('results.html', results=results)

2. Flash Messages — User Feedback

python
from flask import flash
app.secret_key = 'your-secret-key-here'  # Required for flash
@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        if username == 'admin' and password == 'secret':
            flash('Login successful!', 'success')
            return redirect('/dashboard')
        else:
            flash('Invalid credentials!', 'error')
    return render_template('login.html')
html
<!-- In base.html, display flash messages -->
{% with messages = get_flashed_messages(with_categories=true) %}
    {% if messages %}
        <ul class="flashes">
        {% for category, message in messages %}
            <li class="{{ category }}">{{ message }}</li>
        {% endfor %}
        </ul>
    {% endif %}
{% endwith %}

3. Manual Form Validation

python
@app.route('/register', methods=['GET', 'POST'])
def register():
    errors = []
    if request.method == 'POST':
        username = request.form['username'].strip()
        password = request.form['password']
        confirm = request.form['confirm_password']
        # Validation
        if len(username) < 3:
            errors.append('Username must be at least 3 characters')
        if len(password) < 8:
            errors.append('Password must be at least 8 characters')
        if password != confirm:
            errors.append('Passwords do not match')
        if not errors:
            # Save user to database
            flash('Registration successful!', 'success')
            return redirect('/login')
    return render_template('register.html', errors=errors)
html
{% if errors %}
    <ul class="errors">
    {% for error in errors %}
        <li>{{ error }}</li>
    {% endfor %}
    </ul>
{% endif %}

4. WTForms — Advanced Form Handling

WTForms simplifies form definition, rendering, and validation.
python
# pip install flask-wtf
from flask_wtf import FlaskForm
from wtforms import StringField, PasswordField, BooleanField, SubmitField
from wtforms.validators import DataRequired, Email, Length, EqualTo
class RegistrationForm(FlaskForm):
    username = StringField('Username', validators=[
        DataRequired(),
        Length(min=3, max=20)
    ])
    email = StringField('Email', validators=[
        DataRequired(),
        Email()
    ])
    password = PasswordField('Password', validators=[
        DataRequired(),
        Length(min=8)
    ])
    confirm_password = PasswordField('Confirm Password', validators=[
        DataRequired(),
        EqualTo('password')
    ])
    submit = SubmitField('Sign Up')
@app.route('/register', methods=['GET', 'POST'])
def register():
    form = RegistrationForm()
    if form.validate_on_submit():
        # Form is valid — process data
        flash('Registration successful!', 'success')
        return redirect('/login')
    return render_template('register_wtf.html', form=form)
html
<form method="POST" action="">
    {{ form.hidden_tag() }}  <!-- CSRF token -->
    <div>
        {{ form.username.label }}
        {{ form.username(size=20) }}
        {% for error in form.username.errors %}
            <span class="error">{{ error }}</span>
        {% endfor %}
    </div>
    <div>
        {{ form.email.label }}
        {{ form.email() }}
    </div>
    <div>
        {{ form.submit() }}
    </div>
</form>

5. Common Pitfalls

Pitfall 1: Forgetting methods=['POST']

python
@app.route('/login')  # Default: only GET
Fix: @app.route('/login', methods=['GET', 'POST'])

Pitfall 2: Accessing form data before checking method

python
@app.route('/submit', methods=['GET', 'POST'])
# request.form['name'] raises BadRequestKeyError on GET
Fix: Check request.method == 'POST' before accessing form data.

Pitfall 3: Forgetting secret_key for flash/session

RuntimeError: The session is unavailable because no secret key was set.

6. Practice Questions

Q1: How do you access GET parameters in Flask?
Answer: request.args.get('key', 'default') for individual params. request.args is an ImmutableMultiDict. Example: /search?q=flask&page=2request.args.get('q') = "flask". Q2: How do you access POST data?
Answer: request.form['field_name'] (raises KeyError if missing) or request.form.get('field_name') (returns None if missing). Q3: What does form.validate_on_submit() do in WTForms?
Answer: Returns True if the form was submitted (POST) AND all validators pass. It runs all defined validators and populates form.errors with validation error messages. Q4: What is a CSRF token and why is it needed?
Answer: Cross-Site Request Forgery token prevents malicious websites from submitting forms on behalf of an authenticated user. Flask-WTF generates and validates this token automatically. Use form.hidden_tag() in the template. Q5: How do you use flash messages?
Answer: (1) Set app.secret_key. (2) flash('Message', 'category') in routes. (3) In template, loop get_flashed_messages(with_categories=true). Categories help style different message types (success, error, info). Q6: What is the difference between request.form and request.args?
Answer: request.form contains POST data (form body). request.args contains GET data (URL query string). Both are dictionary-like objects. Q7: Write a Flask route that accepts a search query and returns results.
python
@app.route('/search')
def search():
    query = request.args.get('q', '')
    results = Item.query.filter(Item.name.contains(query)).all() if query else []
    return render_template('search.html', query=query, results=results)
Q8: What does WTForms EqualTo validator check?
Answer: It validates that the field's value equals the value of another field (e.g., confirm_password must match password). Usage: EqualTo('password', message='Passwords must match').

📐 Key Concepts

ObjectContentUsage
request.formPOST datarequest.form['username']
request.argsGET query paramsrequest.args.get('q')
flash()User messagesflash('Saved!', 'success')
form.validate_on_submit()WTForms validationif form.validate_on_submit():

🔗 Cross-References

Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.