Flask 1.0 · 45 minutter
Intro til Flask og SQLite: HTTP GET/POST på egen maskin
I denne introduksjonslaben lager du en liten app med én funksjon: Du trykker på en knapp, Flask lagrer statusen i en SQLite-database, og siden viser siste lagrede status.
Målet med oppgaven
Du skal forstå kjernen i en tredelt arkitektur: nettleseren sender HTTP-forespørsler, Flask tolker dem, og SQLite lagrer dataene. Dette er den samme typen kommunikasjon som skjer i større systemer, bare i en veldig liten og synlig versjon.
Hent siden
Nettleseren ber Flask om forsiden. Flask henter siste status fra databasen.
Send status
Skjemaet sender valgt humør til backend-ruten /oppdater.
Lagre data
Statusen lagres i filen intro.db, så dataene overlever
restart.
Hvorfor dette ligner Supabase
I Supabase-introen bruker vi JavaScript i frontend til å lagre data slik:
supabaseClient.from('messages').insert(...). Det ser ut som nettleseren snakker direkte med
databasen.
Under panseret sender Supabase-klienten en HTTP-request til Supabase sin server i skyen. Serveren sjekker API-nøkkel, RLS-policyer og tabellregler før data lagres. I Flask bygger du en enkel versjon av den serveren selv, slik at den skjulte trafikken blir synlig.
Nettleser
HTML-siden viser skjemaet og sender GET eller
POST.
Flask-server
Python-koden tar imot requesten, bestemmer hva som skal skje og lager svaret.
SQLite
Data lagres i intro.db og kan hentes igjen senere.
Flyten i appen
1. Første sidevisning
Nettleseren sender GET /. Flask henter siste rad fra
databasen.
2. Brukeren velger status
Skjemaet sender POST /oppdater med feltet
humoer_input.
3. Flask redirecter
Statusen lagres i SQLite, og brukeren sendes tilbake til forsiden.
Mappestruktur
Lag en mappe som heter introduksjon.
introduksjon/
├── app.py
└── templates/
└── index.html
Steg 1 - Backend: app.py
Denne filen setter opp Flask, lager en SQLite-database og håndterer både GET og POST.
import os
import sqlite3
from flask import Flask, render_template, request, redirect
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
DB_PATH = os.path.join(BASE_DIR, "intro.db")
app = Flask(__name__)
# Opprett en minimal database med en gang serveren starter
with sqlite3.connect(DB_PATH) as conn:
conn.execute("CREATE TABLE IF NOT EXISTS status (tilstand TEXT)")
@app.route("/")
def index():
# HTTP GET: Hent det siste lagrede humøret fra databasen
with sqlite3.connect(DB_PATH) as conn:
cursor = conn.cursor()
cursor.execute("SELECT tilstand FROM status ORDER BY rowid DESC LIMIT 1")
resultat = cursor.fetchone()
gjeldende_humoer = resultat[0] if resultat else "Ingen data ennå"
return render_template("index.html", humoer=gjeldende_humoer)
@app.route("/oppdater", methods=["POST"])
def oppdater():
# HTTP POST: Ta imot dataene som ble sendt i forespørselen
eget_humoer = (request.form.get("eget_humoer") or "").strip()
valgt_humoer = eget_humoer or request.form.get("humoer_input")
with sqlite3.connect(DB_PATH) as conn:
conn.execute("INSERT INTO status (tilstand) VALUES (?)", (valgt_humoer,))
return redirect("/")
if __name__ == "__main__":
app.run(debug=True)
debug=True er nyttig i denne lokale introduksjonslaben fordi Flask viser tydelige feilmeldinger.
Når appen deles med andre maskiner på nettverket, skal du bruke oppsettet i neste modul.
Hva betyr de viktigste delene?
app = Flask(__name__)
Starter Flask-appen. Dette er objektet som holder styr på rutene våre.
@app.route("/")
Bestemmer hva som skjer når nettleseren åpner forsiden med en GET-request.
render_template(...)
Sender HTML-filen tilbake til nettleseren, med variabelen
humoer fylt inn.
request.form.get(...)
Leser verdier som kom fra skjemaet da brukeren trykket på lagre-knappen.
sqlite3.connect(...)
Åpner databasefilen intro.db, slik at Flask kan lese og
lagre data.
redirect("/")
Sender nettleseren tilbake til forsiden etter at statusen er lagret.
Steg 2 - Frontend: templates/index.html
Legg merke til at skjemaet eksplisitt bruker method="POST" og sender data til
/oppdater.
<!DOCTYPE html>
<html lang="no">
<head>
<meta charset="UTF-8">
<title>Humørsjekk</title>
</head>
<body>
<h1>Akkurat nå føler jeg meg: {{ humoer }}</h1>
<form action="/oppdater" method="POST">
<p>Endre status:</p>
<input type="radio" id="gla" name="humoer_input" value="Klar for koding!" checked>
<label for="gla">Klar for koding!</label><br>
<input type="radio" id="troett" name="humoer_input" value="Trenger kaffe...">
<label for="troett">Trenger kaffe...</label><br><br>
<label for="eget_humoer">Eller skriv din egen status:</label><br>
<input type="text" id="eget_humoer" name="eget_humoer" maxlength="60"
placeholder="F.eks. Nysgjerrig på Flask"><br><br>
<button type="submit">Lagre i databasen</button>
</form>
</body>
</html>
Steg 3 - Kjør prosjektet
- Åpne terminalen i mappen
introduksjon. - Lag et virtuelt Python-miljø, slik at Flask installeres lokalt i prosjektet.
- Start serveren og åpne adressen Flask viser, vanligvis
http://127.0.0.1:5000.
.venv, kan prosjektet kjøres lokalt uten internett.
.venv starter med et tomt Python-miljø.
Da må pakkene installeres på nytt i den mappen, for eksempel med python3 -m pip install flask.
python3 -m venv .venv
source .venv/bin/activate
python3 -m pip install flask
python3 app.py
(.venv) foran linjen, bruker du riktig Python-miljø for prosjektet.
Aha-opplevelser i terminalen
1. Se GET
Når siden lastes inn, viser terminalen GET / HTTP/1.1. Det er nettleseren som ber om siden.
2. Se POST
Når du trykker på knappen, viser terminalen POST /oppdater HTTP/1.1. Det er skjemaet som
sender data.
3. Test persistens
Stopp serveren med Ctrl+C og start den igjen. Statusen ligger fortsatt i
intro.db.
intro.db i vanlig tekstbehandler; SQLite-filer
er
binære og ser rotete ut. Stopp eventuelt serveren med Ctrl+C, og kjør:
sqlite3 intro.db "SELECT rowid, tilstand FROM status;"
Som dere ser, bruker vi her en standard SQL-spørring for å hente data fra databasen.
Kontrollspørsmål
- Hva er forskjellen på
GET /ogPOST /oppdater? - Hvorfor bruker vi
redirect("/")etter at data er lagret? - Hvor ligger dataene etter at serveren er stoppet?
- Hva skjuler Supabase for deg som Flask gjør synlig i denne laben?