Week 6 of 16

Forms and Data Flow

GET vs POST, form submissions, and how data moves between browser and Python

Day 27 60 minutes Watch + Read

Day 27 of 80

What You'll Accomplish Today

Part 1: GET vs POST — The Mental Model

GET vs POST

GET — "Give me a page." When you type a URL in your browser, that's a GET request. Data goes in the URL itself: /?search=aerial&platform=kling. GET requests are for reading. They should never change anything on the server.

POST — "Here's some data, process it." When you submit a form, that's a POST request. Data goes in the request body, not the URL. Use POST for adding or changing data — creating a new prompt, deleting a record, submitting a login.

The rule of thumb: GET = read, POST = write.

The difference in practice Python
from flask import Flask, render_template, request

app = Flask(__name__)

# This route only handles GET requests (the default)
@app.route("/")
def home():
    return render_template("index.html")

# This route handles POST requests from a form submission
@app.route("/add", methods=["POST"])
def add_prompt():
    # request.form is a dictionary of the submitted form fields
    platform = request.form["platform"]
    shot = request.form["shot"]
    print(f"Received: {platform} — {shot}")
    return redirect("/")  # send the user back to the home page
methods=["POST"] — By default Flask routes only accept GET. You have to explicitly opt in to POST. You can also do methods=["GET", "POST"] to handle both in one function — Corey shows this pattern in the video.

request.form["platform"] — Flask gives you a global request object whenever a request is being handled. request.form is a dictionary containing everything submitted in the form body. The key matches the name attribute on the HTML input.

The HTML Side of the Form

templates/index.html — the form HTML
<!-- action="/add" — where to send the data -->
<!-- method="post" — how to send it (POST request body) -->
<form action="/add" method="post">

  <!-- name="platform" matches request.form["platform"] in Python -->
  <select name="platform">
    <option value="Kling">Kling</option>
    <option value="Runway">Runway</option>
    <option value="Veo">Veo</option>
  </select>

  <input type="text" name="shot" placeholder="Shot description...">
  <textarea name="prompt" placeholder="Prompt text..."></textarea>

  <button type="submit">Add Prompt</button>
</form>
The name attribute on every input is the key you'll use in request.form. If the input has name="shot", you read it with request.form["shot"]. If the name doesn't match exactly, you'll get a KeyError. Use request.form.get("shot", "") for a safer version that returns an empty string instead of crashing if the field is missing.

Part 2: Today's Videos — Flask Parts 3 & 4

Corey Schafer — Flask Part 3: Forms and User Input

WTForms, form validation, POST handling (~30 min)

Corey Schafer — Flask Part 4: Database Basics

SQLAlchemy intro (~25 min) — you'll use JSON files instead, but the concepts transfer

Note on Part 4 (Database)

Corey uses SQLAlchemy for database storage. You won't use a database — you'll keep storing prompts in your JSON file, the same helpers.py functions from Week 5. But watch how he structures models and CRUD operations. The pattern (create, read, update, delete) is identical. You're just swapping the storage layer.

Part 3: Read — Flask Quickstart Routing

Resource What to focus on
Flask Quickstart — Routing Variable rules (<int:index>, <string:name>), HTTP methods, URL building with url_for()
Variable Rules Are Key

Pay special attention to variable rules like @app.route("/delete/<int:index>"). The <int:index> part captures a number from the URL and passes it to your function as an argument. You'll use this tomorrow for the delete button: /delete/0 deletes prompt at index 0, /delete/3 deletes index 3. Flask handles the URL parsing for you.

Part 4: Practice — A Mini Form App

After watching the videos, build this small app in your flask-practice/ folder. It's a simplified version of what you'll build tomorrow:

flask-practice/form_test.py Python
from flask import Flask, render_template, request, redirect

app = Flask(__name__)

# In-memory list — resets every time the server restarts
# Tomorrow you'll replace this with your JSON helpers
items = []

@app.route("/")
def home():
    return render_template("form_test.html", items=items)

@app.route("/add", methods=["POST"])
def add_item():
    text = request.form.get("text", "")
    if text:
        items.append(text)
    return redirect("/")

@app.route("/delete/<int:index>")
def delete_item(index):
    if 0 <= index < len(items):
        items.pop(index)
    return redirect("/")

if __name__ == "__main__":
    app.run(debug=True)
request.form.get("text", "") — The safer version of request.form["text"]. If the field is missing, returns "" instead of raising a KeyError. Use .get() when in doubt.

redirect("/") — After processing a POST, always redirect instead of rendering a template directly. This prevents the browser's "resubmit form" warning when the user hits the back button. This pattern is called Post/Redirect/Get (PRG).

The redirect() Pattern — Why It Matters

Post → Redirect → Get (PRG)

After a POST request, always call redirect() to send the user to a GET route. If you render a template directly after a POST and the user hits the browser back button or refreshes, the browser will try to resubmit the form — which means your data gets written twice.

Pattern: POST route does the work → redirect("/"); → GET route renders the updated page. Every web framework follows this pattern.

End of Day Checklist

Tomorrow — The Real Thing

Tomorrow you build the actual Prompt Vault web app. You'll reuse helpers.py from Week 5 as-is, add a proper app.py with three routes, and build a dark-themed HTML template. Your CLI prompt tool becomes a browser app.