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 eit lettvekts Python-rammeverk for webutvikling. Det er perfekt for å lære backend-utvikling fordi det er enkelt å kome i gang med, men kraftig nok for seriøse applikasjonar.

I dette kapittelet skal vi byggje ein backend-applikasjon med Flask som handterer ruter, templates, skjema 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)

Køyr appen:

python app.py

Applikasjonen køyrer no på http://localhost:5000

Nøkkelkonsept:
- @app.route() definerer URL-ruter
- Funksjonen returnerer innhald til brukaren
- debug=True gir betre feilmeldingar og auto-reload

✏️Ruter og URL-parameter
Ulike HTTP-metodar:
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-parameter:

@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 lèt deg generere dynamisk HTML.

Prosjektstruktur:

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

Templates må liggje i mappa "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 funksjonar
Variablar:
<h1>{{ tittel }}</h1>
<p>{{ beskrivelse }}</p>

Løkker:

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

Vilkår:

{% 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 %}

✏️Skjema 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 å handtere 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-meldingar krev secret key:

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

Vise flash-meldingar 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 brukarautentisering
Sessions lèt deg lagre brukardata mellom førespurnader (f.eks. om nokon er innlogga).

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 blir lagra i cookies (kryptert med secret_key)
- ALDRI hardkod passord i produksjon - bruk bcrypt/hashing
- Secret key bør hentast frå miljøvariablar

No skal du løyse oppgåver om Flask, ruter, templates og sessions.

Oppsummering

I dette kapittelet har du lært:

- Backend med Flask: serverlogikk i Python.
- Ruter og URL-parameter: handtere ulike førespurnader.
- Jinja2: templatemotor for dynamiske sider.
- Skjema og POST-data: motta data frå brukaren.
- Sessions: brukarautentisering og tilstand.

Nøkkelbegrep


BegrepForklaring
BackendServersida av ein applikasjon
Jinja2Flask sin templatemotor
SessionLagrar brukartilstand mellom førespurnader

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.