Tilbake
6.3
Backend med Python og Flask

6.3 Backend med Python og Flask

Serverside-programmering, templating og sesjonshåndtering.

65 min
6 oppgaver
FlaskJinja2SesjonerRuter
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 6 oppgaver

Flask er et lettvekts Python-rammeverk for webutvikling. Det er perfekt for å lære backend-utvikling fordi det er enkelt å komme i gang med, men kraftig nok for seriøse applikasjoner.

I dette kapittelet skal vi bygge en backend-applikasjon med Flask som håndterer ruter, templates, skjemaer og sessions.

Installasjon:
pip install flask

Minimal Flask-app:

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hjem():
    return 'Velkommen til min Flask-app!'

if __name__ == '__main__':
    app.run(debug=True)

Kjør appen:

python app.py

Applikasjonen kjører nå på http://localhost:5000

Nøkkelkonsepter:
- @app.route() definerer URL-ruter
- Funksjonen returnerer innhold til brukeren
- debug=True gir bedre feilmeldinger og auto-reload

✏️Ruter og URL-parametere
Ulike HTTP-metoder:
from flask import Flask, request

app = Flask(__name__)

# GET (standard)
@app.route('/bruker')
def hent_bruker():
    return 'Henter bruker'

# POST
@app.route('/bruker', methods=['POST'])
def opprett_bruker():
    data = request.json
    return f'Oppretter bruker: {data}'

# PUT
@app.route('/bruker/<int:id>', methods=['PUT'])
def oppdater_bruker(id):
    return f'Oppdaterer bruker {id}'

# DELETE
@app.route('/bruker/<int:id>', methods=['DELETE'])
def slett_bruker(id):
    return f'Sletter bruker {id}'

URL-parametere:

@app.route('/produkt/<int:produkt_id>')
def vis_produkt(produkt_id):
    return f'Viser produkt {produkt_id}'

@app.route('/bruker/<string:brukernavn>')
def vis_bruker(brukernavn):
    return f'Bruker: {brukernavn}'

# Query-parametere: /sok?q=flask
@app.route('/sok')
def sok():
    query = request.args.get('q', '')
    return f'Søker etter: {query}'

Jinja2 er Flask sitt template-system som lar deg generere dynamisk HTML.

Prosjektstruktur:

mitt-prosjekt/
├── app.py
├── templates/
│   ├── base.html
│   ├── hjem.html
│   └── produkt.html
└── static/
    ├── style.css
    └── script.js

Templates må ligge i mappen "templates"

Sende data til template:

from flask import render_template

@app.route('/velkomst/<navn>')
def velkomst(navn):
    return render_template('velkomst.html', brukernavn=navn)

Template (velkomst.html):

<!DOCTYPE html>
<html>
<head>
    <title>Velkommen</title>
</head>
<body>
    <h1>Hei, {{ brukernavn }}!</h1>
</body>
</html>
✏️Jinja2 syntaks og funksjoner
Variabler:
<h1>{{ tittel }}</h1>
<p>{{ beskrivelse }}</p>

Løkker:

<ul>
{% for produkt in produkter %}
    <li>{{ produkt.navn }} - {{ produkt.pris }} kr</li>
{% endfor %}
</ul>

Betingelser:

{% if bruker_innlogget %}
    <p>Velkommen tilbake!</p>
{% else %}
    <p>Vennligst logg inn</p>
{% endif %}

Template-arv (base.html):

<!DOCTYPE html>
<html>
<head>
    <title>{% block title %}Min side{% endblock %}</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
    <nav>
        <a href="/">Hjem</a>
        <a href="/om">Om</a>
    </nav>

    {% block content %}{% endblock %}

    <footer>© 2025 Min App</footer>
</body>
</html>

Child template (hjem.html):

{% extends "base.html" %}

{% block title %}Hjemmeside{% endblock %}

{% block content %}
    <h1>Velkommen!</h1>
    <p>Dette er innholdet.</p>
{% endblock %}

✏️Skjemaer og POST-data
HTML-skjema (kontakt.html):
<form method="POST" action="/send-melding">
    <input type="text" name="navn" placeholder="Ditt navn" required>
    <input type="email" name="epost" placeholder="Din e-post" required>
    <textarea name="melding" placeholder="Din melding" required></textarea>
    <button type="submit">Send</button>
</form>

Flask route for å håndtere skjema:

from flask import Flask, render_template, request, redirect, url_for, flash

@app.route('/kontakt')
def kontakt():
    return render_template('kontakt.html')

@app.route('/send-melding', methods=['POST'])
def send_melding():
    navn = request.form.get('navn')
    epost = request.form.get('epost')
    melding = request.form.get('melding')

    # Validering
    if not navn or not epost or not melding:
        flash('Alle felt må fylles ut', 'error')
        return redirect(url_for('kontakt'))

    # Lagre melding (database, e-post, etc.)
    print(f'Mottatt melding fra {navn} ({epost}): {melding}')

    flash('Melding sendt!', 'success')
    return redirect(url_for('kontakt'))

Flash-meldinger krever secret key:

app.secret_key = 'din-hemmelige-noekkel-her'

Vise flash-meldinger i template:

{% with messages = get_flashed_messages(with_categories=true) %}
  {% if messages %}
    {% for category, message in messages %}
      <div class="alert alert-{{ category }}">{{ message }}</div>
    {% endfor %}
  {% endif %}
{% endwith %}

✏️Sessions og brukerautentisering
Sessions lar deg lagre brukerdata mellom forespørsler (f.eks. om noen er innlogget).

Enkel innlogging:

from flask import Flask, session, redirect, url_for, request, render_template

app = Flask(__name__)
app.secret_key = 'supersecretkey123'

# "Database" (hardkodet for eksempel)
BRUKERE = {
    'admin': 'passord123',
    'ola': 'test456'
}

@app.route('/')
def hjem():
    if 'brukernavn' in session:
        return f'Logget inn som: {session["brukernavn"]} <a href="/logout">Logg ut</a>'
    return 'Du er ikke logget inn. <a href="/login">Logg inn</a>'

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        brukernavn = request.form['brukernavn']
        passord = request.form['passord']

        if brukernavn in BRUKERE and BRUKERE[brukernavn] == passord:
            session['brukernavn'] = brukernavn
            return redirect(url_for('hjem'))
        else:
            return 'Ugyldig brukernavn eller passord'

    return '''
        <form method="post">
            <input type="text" name="brukernavn" placeholder="Brukernavn">
            <input type="password" name="passord" placeholder="Passord">
            <button type="submit">Logg inn</button>
        </form>
    '''

@app.route('/logout')
def logout():
    session.pop('brukernavn', None)
    return redirect(url_for('hjem'))

Viktig:
- Sessions lagres i cookies (kryptert med secret_key)
- ALDRI hardkod passord i produksjon - bruk bcrypt/hashing
- Secret key bør hentes fra miljøvariabler

Nå skal du løse oppgaver om Flask, ruter, templates og sessions.

Oppsummering

I dette kapittelet har du lært:

- Backend med Flask: serverlogikk i Python.
- Ruter og URL-parametere: håndtere ulike foresporsler.
- Jinja2: templatemotor for dynamiske sider.
- Skjemaer og POST-data: motta data fra brukeren.
- Sessions: brukerautentisering og tilstand.

Noekkelbegreper


BegrepForklaring
BackendServersiden av en applikasjon
Jinja2Flask sin templatemotor
SessionLagrer brukertilstand mellom foresporsler

Oppgaver

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.