OIM3640 - Problem Solving and Software Design

Flask Web Apps

contain

Why Flask?

So far: your Python scripts run in the terminal. What if anyone could use your program in a browser?

  • Flask turns your Python code into a website
    • You write Python, Flask handles the web part
  • Why Flask? Simple, beginner-friendly, used in production
    • Pinterest, Zillow, Twilio, Reddit, Netflix, ...
  • There's also Django (more powerful, more complex) - Flask is the right starting point

How URLs Work

Every website maps URLs to pages. Think about TikTok:

URL What you see
MyTiktok.com/ Home feed
MyTiktok.com/new Upload a new video
MyTiktok.com/1 Video #1
MyTiktok.com/1/edit Edit video #1

In Flask, you decide what each URL does:

@app.get('/new')         # when someone visits /new
def upload():            # run this function
    return 'Upload page'

Your First Flask App

Create a folder helloflask/, then create app.py:

from flask import Flask

app = Flask(__name__)

@app.get('/')
def hello():
    return 'Hello, World!'

if __name__ == '__main__':
    app.run(debug=True)
cd helloflask
pip install flask
python app.py     # visit http://127.0.0.1:5000

More Routes

@app.get('/hello/<name>')
def hello(name):
    return f'Hello, {name}!'

Visit http://127.0.0.1:5000/hello/Zhi --> shows "Hello, Zhi!"

@app.get('/square/<int:n>')
def square(n):
    return f'{n} squared is {n ** 2}'

Visit http://127.0.0.1:5000/square/7 --> shows "7 squared is 49"

<name> and <int:n> capture parts of the URL as function arguments.

Flask Templates

Returning raw strings is limited. Use templates (HTML files):

app.py:

from flask import Flask, render_template

@app.get('/hello/<name>')
def greet(name):
    return render_template('hello.html', name=name)

templates/hello.html:

<h1>Hello, {{ name }}!</h1>
<p>Welcome to my Flask app.</p>

{{ name }} is replaced by the value passed from Python.

HTML Forms

Forms let users send data to your Flask app:

<form method="POST" action="/search">
    <label>Enter a place:</label>
    <input type="text" name="place">
    <button type="submit">Search</button>
</form>
  • method="POST" - sends data in the request body (not in the URL)
  • action="/search" - where to send the form data
  • name="place" - the key your Python code uses to read the input

GET vs POST

GET POST
Purpose Retrieve/display data Submit/send data
Data location In the URL (?q=hello) In the request body (hidden)
Example Loading a page Submitting a form
Flask decorator @app.get(...) @app.post(...)

One function per job - cleaner than if request.method == 'POST'.

Handling Form Submissions

from flask import Flask, request, render_template

app = Flask(__name__)

@app.get('/')
def index():
    return render_template('index.html')

@app.post('/search')
def search():
    place = request.form['place']
    return render_template('result.html', place=place)

@app.get shows the form, @app.post handles the submission.
request.form['place'] gets the value the user typed.

Putting It Together

templates/index.html:

<h1>Place Search</h1>
<form method="POST" action="/search">
    <input type="text" name="place" placeholder="e.g., Boston Common">
    <button type="submit">Search</button>
</form>

templates/result.html:

<h1>Results for {{ place }}</h1>
<p>You searched for: {{ place }}</p>
<a href="/">Search again</a>

Template Inheritance

templates/base.html:

<html>
<head><title>My App</title></head>
<body>
    <nav><a href="/">Home</a></nav>
    {% block content %}{% endblock %}
</body>
</html>

templates/index.html:

{% extends "base.html" %}
{% block content %}
<h1>Welcome!</h1>
{% endblock %}

Flask Project Structure

myapp/
├── app.py              # routes and logic
├── mbta_helper.py      # API helper functions
├── .env                # API keys (never commit!)
├── .gitignore          # includes .env
├── templates/
│   ├── base.html       # shared layout
│   ├── index.html      # home page with form
│   └── result.html     # results page
└── static/
    └── style.css       # optional CSS

Separate helper functions from Flask routes.

What About @app.route()?

You'll see this older style online:

@app.route('/search', methods=['GET', 'POST'])
def search():
    if request.method == 'POST':
        # handle form
        ...
    return render_template('search.html')

@app.get / @app.post (Flask 2.0+) are the modern way:

  • One function per HTTP method - clearer and simpler
  • Same pattern as FastAPI, Express, and other frameworks

Flask Resources