Tilbake
5.3
Databaser i Python med SQLite

5.3 Databaser i Python med SQLite

Koble til og bruke databaser fra Python-kode.

65 min
6 oppgaver
SQLitePythonCRUDParameteriserte spørringer
Du leser den lesevennlige versjonen
Din fremgang i kapitlet
0 / 6 oppgaver

Python møter databasen

Nå skal vi koble sammen to ting du allerede kan: Python og databaser. SQLite er en lettvektsdatabase som kommer innebygd i Python – perfekt for lokale applikasjoner, prototyper og mindre systemer. Du trenger ingen egen server; hele databasen er bare en fil.

Du bruker den innebygde modulen sqlite3. Du kobler til en database med sqlite3.connect('skole.db') – filen opprettes hvis den ikke finnes. For testing kan du bruke ':memory:', som lager en database som bare lever i RAM. Deretter lager du en cursor, som er objektet som faktisk utfører SQL-kommandoer og henter resultater. Den anbefalte måten er en with-blokk, slik at forbindelsen lukkes automatisk:

import sqlite3
with sqlite3.connect('skole.db') as conn:
    cursor = conn.cursor()
    cursor.execute('''CREATE TABLE IF NOT EXISTS Elev (
        elevID INTEGER PRIMARY KEY AUTOINCREMENT,
        navn TEXT NOT NULL,
        epost TEXT UNIQUE)''')
    conn.commit()

Legg merke til tre ting. IF NOT EXISTS hindrer feil hvis tabellen finnes fra før. AUTOINCREMENT lager automatisk økende ID-er. Og conn.commit() må kalles for å faktisk lagre endringene til databasen – uten den forsvinner de.

📝Oppgave Quiz 1

CRUD i Python

De fire grunnoperasjonene – Create, Read, Update, Delete – utføres alle gjennom cursoren. For å opprette bruker du INSERT med parametere, og henter id-en til den nye raden med cursor.lastrowid. For å lese har du tre nyttige metoder: fetchone() henter én rad, fetchall() henter alle, og du kan også iterere direkte over cursoren rad for rad – det siste er smart for store resultater fordi du slipper å laste alt inn i minnet samtidig:

cursor.execute("SELECT * FROM Elev WHERE elevID = ?", (1,))
elev = cursor.fetchone()   # én rad som tuppel

For å oppdatere bruker du UPDATE, og cursor.rowcount forteller hvor mange rader som ble endret. For å slette bruker du DELETE på tilsvarende måte. Som standard kommer hver rad tilbake som en tuppel, der du må bruke indekser som elev[0]. Det blir fort uoversiktlig.

Heldigvis finnes et triks: row factory. Setter du conn.row_factory = sqlite3.Row, kan du etterpå hente verdier med kolonnenavn i stedet for indeks – elev['navn'] i stedet for elev[1] – og til og med konvertere raden til en vanlig dictionary med dict(elev). Dette gjør koden langt mer lesbar og mindre feilutsatt. En god vane er også å pakke CRUD-logikken inn i en klasse, slik at all databasekoden samles ett sted.

📝Oppgave Quiz 2

SQL injection, feil og transaksjoner

Nå kommer den viktigste lærdommen i hele kapittelet. SQL injection er en av de farligste sikkerhetssvakhetene som finnes. Bygger du en spørring ved å lime brukerinput rett inn med f-strenger, åpner du døren på vidt gap. Skriver en angriper Ole' OR '1'='1 der du forventet et navn, blir spørringen ... WHERE navn = 'Ole' OR '1'='1', og siden '1'='1' alltid er sant, returneres alle rader. Enda verre: med '; DROP TABLE Elev; -- kan angriperen slette hele tabellen.

Løsningen er parameteriserte spørringer. Du skriver ? der verdiene skal inn, og lar Python sette dem trygt inn:

cursor.execute("SELECT * FROM Elev WHERE navn = ?", (bruker_input,))

Regelen er absolutt: bruk alltid ? for verdier, aldri f-strenger eller pluss-konkatenering. Da escaper Python verdien automatisk, og injeksjon blir umulig.

God databasekode håndterer også feil. Med try-except kan du fange sqlite3.IntegrityError (for eksempel en duplikat-epost mot en UNIQUE-regel), sqlite3.OperationalError (som en tabell som ikke finnes) og den generelle sqlite3.Error. Til slutt: en transaksjon er en sekvens av operasjoner som enten utføres helt eller ikke i det hele tatt. Skal du sette inn en elev og en tilhørende karakter, vil du ikke at det ene skal lykkes og det andre feile. Går alt bra, kaller du conn.commit(). Går noe galt, kaller du conn.rollback(), som angrer alle endringer siden forrige commit. Slik holder databasen seg konsistent selv når noe svikter.

📝Oppgave Quiz 3

Oppsummering

Vi koblet Python til SQLite via sqlite3-modulen: du connecter til en fildatabase, lager en cursor, kjører SQL og kaller commit() for å lagre. CRUD-operasjonene utføres gjennom cursoren, med fetchone()/fetchall() for lesing, lastrowid for nye ID-er, og sqlite3.Row for å hente verdier ved kolonnenavn.

Den viktigste lærdommen var sikkerhet: bruk parameteriserte spørringer med ? for å hindre SQL injection – aldri f-strenger eller konkatenering. God kode fanger feil med try-except, og transaksjoner med commit og rollback sikrer at sammensatte operasjoner enten lykkes helt eller angres helt. Med dette kan du bygge ekte databaseapplikasjoner i Python. I neste kapittel ser vi på alternativene til relasjonsdatabaser: NoSQL.

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.