Hoe gebruik je webformulieren in een Flask-toepassing

De auteur koos ervoor om een donatie te doen aan het Vrij en Open Source Fonds als onderdeel van het Write for DOnations programma.

Inleiding

Webformulieren, zoals tekstvelden en tekstgebieden, geven gebruikers de mogelijkheid om gegevens naar uw applicatie te verzenden om deze te gebruiken om een actie uit te voeren of om grotere tekstblokken naar de applicatie te sturen. Bijvoorbeeld, in een sociale mediatoepassing, kunt u gebruikers een veld geven waar ze nieuwe inhoud aan hun pagina’s kunnen toevoegen. Een ander voorbeeld is een inlogpagina, waar u de gebruiker een tekstveld geeft om hun gebruikersnaam in te voeren en een wachtwoordveld om hun wachtwoord in te voeren. De server (uw Flask-applicatie in dit geval) gebruikt de gegevens die de gebruiker verzendt en logt hen in als de gegevens geldig zijn, of antwoordt met een bericht zoals Ongeldige gegevens! om de gebruiker te informeren dat de ingediende gegevens niet correct zijn.

Flask is een lichtgewicht Python webframework dat nuttige tools en functies biedt voor het maken van webapplicaties in de Python taal. In deze tutorial bouw je een kleine webapplicatie die laat zien hoe je webformulieren kunt gebruiken. De applicatie zal een pagina hebben voor het weergeven van berichten die zijn opgeslagen in een Python lijst, en een pagina voor het toevoegen van nieuwe berichten. Je zult ook message flashing gebruiken om gebruikers te informeren over een fout wanneer ze ongeldige gegevens indienen.

Vereisten

Stap 1 — Berichten Weergeven

In deze stap maak je een Flask applicatie met een indexpagina voor het weergeven van berichten die zijn opgeslagen in een lijst van Python dictionaries.

Open eerst een nieuw bestand genaamd app.py voor bewerking:

  1. nano app.py

Voeg de volgende code toe in het app.py bestand om een Flask server met één route te creëren:

flask_app/app.py
from flask import Flask, render_template

app = Flask(__name__)

messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]

@app.route('/')
def index():
    return render_template('index.html', messages=messages)

Sla het bestand op en sluit het.

In dit bestand importeer je eerst de Flask klasse en de render_template() functie uit het flask pakket. Vervolgens gebruik je de Flask klasse om een nieuw applicatie-exemplaar te maken genaamd app, waarbij de speciale __name__ variabele wordt doorgegeven, wat Flask nodig heeft om enkele paden achter de schermen in te stellen. Het renderen van sjablonen wordt behandeld in de tutorial Hoe Sjablonen Te Gebruiken in Een Flask Applicatie.

Vervolgens maak je een globale Python lijst genaamd messages, die Python dictionaries bevat. Elke dictionary heeft twee sleutels: title voor de titel van het bericht en content voor de inhoud van het bericht. Dit is een vereenvoudigd voorbeeld van een datastorage methode; in een echte situatie zou je een database gebruiken die de gegevens permanent opslaat en je in staat stelt om deze efficiënter te manipuleren.

Na het aanmaken van de Python lijst, gebruik je de @app.route() decorator om een view functie te maken genaamd index(). Hierin geef je een aanroep terug naar de render_template() functie, die aangeeft dat de route een HTML template moet weergeven. Je noemt deze template index.html (je zult het later aanmaken) en je geeft er een variabele genaamd messages aan door. Deze variabele bevat de messages lijst die je eerder hebt gedeclareerd als waarde en maakt deze beschikbaar voor de HTML template. View functies worden behandeld in de tutorial Hoe je je eerste webapplicatie maakt met Flask en Python 3.

Daarna, maak een templates map aan in je flask_app directory waar Flask naar templates zoekt, en open een template bestand genaamd base.html, dat code zal bevatten die andere templates zullen erven om codeherhaling te voorkomen:

  1. mkdir templates
  2. nano templates/base.html

Voeg de volgende code toe in het base.html bestand om de basis template te maken met een navigatiebalk en een inhoudsblok:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Sla het bestand op en sluit het.

Deze basissjabloon bevat alle HTML-boilerplate die je nodig hebt om opnieuw te gebruiken in je andere sjablonen. Het title blok wordt vervangen om een titel in te stellen voor elke pagina, en het content blok wordt vervangen door de inhoud van elke pagina. De navigatiebalk heeft twee links, één voor de indexpagina waar je de url_for() helperfunctie gebruikt om te linken naar de index() viewfunctie, en de andere voor een About-pagina als je ervoor kiest om er een in je applicatie op te nemen.

Open vervolgens een sjabloon genaamd index.html. Dit is het sjabloon dat je hebt genoemd in het app.py bestand:

  1. nano templates/index.html

Voeg de volgende code toe:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Messages {% endblock %}</h1>
    {% for message in messages %}
        <div class='message'>
            <h3>{{ message['title'] }}</h3>
            <p>{{ message['content'] }}</p>
        </div>
    {% endfor %}
{% endblock %}

Bewaar en sluit het bestand.

In deze code breid je het base.html sjabloon uit en vervang je de inhoud van het content blok. Je gebruikt een <h1> kop die ook als titel dient.

Je gebruikt een Jinja for loop in de regel {% for message in messages %} om door elk bericht in de messages lijst te gaan. Je gebruikt een <div> tag om de titel en inhoud van het bericht te bevatten. Je toont de titel in een <h3> kop en de inhoud in een <p> tag.

Terwijl je in je flask_app directory bent met je virtuele omgeving geactiveerd, vertel je Flask over de applicatie (app.py in dit geval) met behulp van de FLASK_APP omgevingsvariabele:

  1. export FLASK_APP=app

Stel vervolgens de omgevingsvariabele FLASK_ENV in op development om de applicatie in ontwikkelingsmodus te draaien en toegang te krijgen tot de debugger. Voor meer informatie over de Flask debugger, zie Hoe Fouten Af te Handelen in een Flask Applicatie. Gebruik de volgende opdrachten om dit te doen (op Windows, gebruik set in plaats van export):

  1. export FLASK_ENV=development

Start vervolgens de applicatie:

  1. flask run

Met de ontwikkelingsserver actief, bezoek de volgende URL met je browser:

http://127.0.0.1:5000/

Je zult de berichten in de messages lijst zien die op de indexpagina worden weergegeven:

Nu je je webapplicatie hebt ingesteld en de berichten hebt weergegeven, heb je een manier nodig om gebruikers in staat te stellen nieuwe berichten toe te voegen aan de indexpagina. Dit gebeurt via webformulieren, die je in de volgende stap zult instellen.

Stap 2 — Het Instellen van Formulieren

In deze stap zult u een pagina in uw applicatie creëren waarmee gebruikers nieuwe berichten aan de lijst van berichten kunnen toevoegen via een webformulier.

Laat de ontwikkelingsserver draaien en open een nieuw terminalvenster.

Open eerst je app.py bestand:

  1. nano app.py

Voeg de volgende route toe aan het einde van het bestand:

flask_app/app.py
# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    return render_template('create.html')

Sla het bestand op en sluit het.

Deze /create route heeft de methods parameter met de tuple ('GET', 'POST') om zowel GET als POST verzoeken te accepteren. GET en POST zijn HTTP-methoden. Standaard worden alleen GET verzoeken geaccepteerd, die worden gebruikt om gegevens op te halen, zoals het vragen van de server om een indexpagina of een About-pagina. POST verzoeken worden gebruikt om gegevens in te dienen bij een specifieke route, wat vaak de gegevens op de server verandert.

In dit voorbeeld vraag je de create pagina op met een GET verzoek. De Create-pagina zal een webformulier hebben met invoervelden en een Verzenden-knop. Wanneer een gebruiker het webformulier invult en op de Verzenden-knop klikt, wordt een POST verzoek verstuurd naar de /create route. Daar behandel je het verzoek, valideer je de ingediende gegevens om ervoor te zorgen dat de gebruiker geen leeg formulier heeft ingediend, en voeg je het toe aan de messages lijst.

De create() weergavefunctie doet momenteel slechts één ding: rendert een sjabloon genaamd create.html wanneer het een regulier GET-verzoek ontvangt. Je gaat nu dit sjabloon maken en vervolgens de functie aanpassen om POST verzoeken in de volgende stap te behandelen.

Open een nieuw sjabloonbestand genaamd create.html:

  1. nano templates/create.html

Voeg de volgende code toe:

flask_app/templates/create.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Add a New Message {% endblock %}</h1>
    <form method="post">
        <label for="title">Title</label>
        <br>
        <input type="text" name="title"
               placeholder="Message title"
               value="{{ request.form['title'] }}"></input>
        <br>

        <label for="content">Message Content</label>
        <br>
        <textarea name="content"
                  placeholder="Message content"
                  rows="15"
                  cols="60"
                  >{{ request.form['content'] }}</textarea>
        <br>
        <button type="submit">Submit</button>
    </form>
{% endblock %}

Bewaar en sluit het bestand.

In deze code breid je de base.html template uit en vervang je het content blok door een <h1> kop die als titel voor de pagina dient. In de <form> tag stel je het method attribuut in op post zodat de formuliergegevens naar de server worden gestuurd als een POST verzoek.

In het formulier heb je een tekstinvoerveld met de naam title; dit is de naam die je in de applicatie gebruikt om toegang te krijgen tot de titel formuliergegevens. Je geeft de <input> tag een value van {{ request.form['title'] }}. Dit is handig om de gegevens die de gebruiker invoert te herstellen, zodat ze niet verloren gaan als er iets misgaat. Bijvoorbeeld, als de gebruiker de vereiste content tekstgebied vergeet in te vullen, wordt er een verzoek naar de server gestuurd en komt er een foutmelding terug als reactie, maar de gegevens in de titel gaan niet verloren omdat ze worden opgeslagen in het request globale object, en kunnen worden benaderd via request.form['title'].

Na het titelinvoerveld voeg je een tekstgebied toe met de naam content met de waarde {{ request.form['content'] }} om dezelfde redenen als eerder genoemd.

Tot slot heb je een Verzendknop aan het einde van het formulier.

Nu, met de ontwikkelingsserver draaiend, gebruik je je browser om naar de /create route te navigeren:

http://127.0.0.1:5000/create

Je zult een “Voeg een Nieuw Bericht Toe” pagina zien met een invoerveld voor een berichttitel, een tekstgebied voor de inhoud van het bericht en een Verzendknop.

Dit formulier verzendt een POST verzoek naar uw create() weergavefunctie. Er is echter nog geen code om een POST verzoek af te handelen in de functie, dus er gebeurt niets na het invullen van het formulier en het indienen ervan. In de volgende stap zult u het binnenkomende POST verzoek afhandelen wanneer een formulier wordt ingediend. U zult controleren of de ingediende gegevens geldig zijn (niet leeg) en de berichttitel en inhoud toevoegen aan de messages lijst.

Stap 3 — Afhandeling van formulierverzoeken

In deze stap zult u formulierverzoeken aan de applicatiezijde afhandelen. U zult toegang krijgen tot de formuliergegevens die de gebruiker indient via het formulier dat u in de vorige stap hebt gemaakt en deze toevoegen aan de lijst met berichten. U zult ook flitsberichten gebruiken om gebruikers te informeren wanneer ze ongeldige gegevens indienen. Het flitsbericht wordt slechts één keer getoond en verdwijnt bij het volgende verzoek (als u bijvoorbeeld naar een andere pagina navigeert).

Open het app.py bestand voor bewerking:

  1. nano app.py

Eerst zult u het volgende importeren uit het Flask framework:

  • Het globale request object om toegang te krijgen tot binnenkomende verzoekgegevens die worden ingediend via het HTML-formulier dat u in de laatste stap heeft gebouwd.
  • De url_for() functie om URL’s te genereren.
  • De flash() functie om een bericht te tonen wanneer een verzoek wordt verwerkt (om de gebruiker te informeren dat alles goed ging, of om hen te informeren over een probleem als de ingediende gegevens niet geldig zijn).
  • De redirect() functie om de client naar een andere locatie te sturen.

Voeg deze imports toe aan de eerste regel in het bestand:

flask_app/app.py
from flask import Flask, render_template, request, url_for, flash, redirect

# ...

De flash() functie slaat geflashed berichten op in de browser sessie van de client, wat het instellen van een geheime sleutel vereist. Deze geheime sleutel wordt gebruikt om sessies te beveiligen, waardoor Flask informatie kan onthouden van het ene naar het andere verzoek, zoals van de nieuwe berichtenpagina naar de indexpagina. De gebruiker kan de informatie die in de sessie is opgeslagen benaderen, maar kan deze niet wijzigen tenzij hij de geheime sleutel heeft, dus je moet nooit toestaan dat iemand toegang krijgt tot je geheime sleutel. Zie de Flask documentatie over sessies voor meer informatie.

De geheime sleutel moet een lange willekeurige string zijn. Je kunt een geheime sleutel genereren met behulp van de os module met de os.urandom() methode, die een string van willekeurige bytes retourneert, geschikt voor cryptografisch gebruik. Om een willekeurige string te krijgen met behulp daarvan, open een nieuwe terminal en open de Python interactieve shell met de volgende commando:

  1. python

In de Python interactieve shell, importeer de os module uit de standaardbibliotheek en roep de os.urandom() methode als volgt aan:

  1. import os
  2. os.urandom(24).hex()

Je krijgt een string die lijkt op het volgende:

Output
'df0331cefc6c2b9a5d0208a726a5d1c0fd37324feba25506'

Je kunt de string die je krijgt als je geheime sleutel gebruiken.

Om de geheime sleutel in te stellen, voeg een SECRET_KEY configuratie toe aan je applicatie via het app.config object. Voeg deze direct toe na de definitie van app voordat je de messages variabele definieert:

flask_app/app.py

# ...
app = Flask(__name__)
app.config['SECRET_KEY'] = 'your secret key'


messages = [{'title': 'Message One',
             'content': 'Message One Content'},
            {'title': 'Message Two',
             'content': 'Message Two Content'}
            ]
# ...

Vervolgens, wijzig de create() view functie om precies als volgt te zien:

flask_app/app.py
# ...

@app.route('/create/', methods=('GET', 'POST'))
def create():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']

        if not title:
            flash('Title is required!')
        elif not content:
            flash('Content is required!')
        else:
            messages.append({'title': title, 'content': content})
            return redirect(url_for('index'))

    return render_template('create.html')

In de if statement zorg je ervoor dat de code erna alleen wordt uitgevoerd wanneer de request een POST request is via de vergelijking request.method == 'POST'.

Je haalt vervolgens de ingediende titel en inhoud op uit het request.form object dat je toegang geeft tot de formuliergegevens in de aanvraag. Als de titel niet is opgegeven, zou de voorwaarde if not title vervuld worden. In dat geval toon je een bericht aan de gebruiker dat de titel verplicht is met de flash() functie. Dit voegt het bericht toe aan een lijst met geflashede berichten. Later zullen deze berichten op de pagina worden weergegeven als onderdeel van de base.html template. Op dezelfde manier, als de inhoud niet is opgegeven, zal de voorwaarde elif not content vervuld worden. Als dat het geval is, voeg je het 'Inhoud is verplicht!' bericht toe aan de lijst met geflashede berichten.

Als de titel en de inhoud van het bericht correct zijn ingediend, gebruik je de regel messages.append({'title': title, 'content': content}) om een nieuw dictionary toe te voegen aan de messages lijst, met de titel en inhoud die de gebruiker heeft opgegeven. Vervolgens gebruik je de redirect() functie om gebruikers door te sturen naar de indexpagina. Je gebruikt de url_for() functie om te linken naar de indexpagina.

Bewaar en sluit het bestand.

Navigeer nu naar de /create route met je webbrowser:

http://127.0.0.1:5000/create

Vul het formulier in met een titel naar keuze en wat inhoud. Zodra je het formulier indient, zie je het nieuwe bericht op de indexpagina vermeld.

Tot slot zul je geflashede berichten weergeven en een link toevoegen voor de “Nieuw Bericht” pagina aan de navigatiebalk in de base.html template om gemakkelijk toegang te hebben tot deze nieuwe pagina. Open het base template bestand:

  1. nano templates/base.html

Bewerk het bestand door een nieuwe ``-tag toe te voegen na de FlaskApp-link in de navigatiebalk binnen de `

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        .message {
            padding: 10px;
            margin: 5px;
            background-color: #f3f3f3
        }
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }

        .alert {
            padding: 20px;
            margin: 5px;
            color: #970020;
            background-color: #ffd5de;
        }

    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('index') }}">FlaskApp</a>
        <a href="{{ url_for('create') }}">Create</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% for message in get_flashed_messages() %}
            <div class="alert">{{ message }}</div>
        {% endfor %}
        {% block content %} {% endblock %}
    </div>
</body>
</html>

Sla het bestand op en sluit het, en herlaad vervolgens `https://127.0.0.1:5000` in je browser. De navigatiebalk heeft nu een “Create”-item dat naar de `/create`-route linkt.

Om te zien hoe geflashede berichten werken, ga naar de “Create”-pagina en klik op de Submit-knop zonder de twee velden in te vullen. Je ontvangt een bericht dat er zo uitziet:

Ga terug naar de indexpagina en je zult zien dat de geflashede berichten onder de navigatiebalk verdwijnen, zelfs al worden ze weergegeven als onderdeel van de basispagina. Als ze geen geflashede berichten waren, zouden ze ook op de indexpagina worden weergegeven, omdat deze ook overneemt van de basispagina.

Probeer het formulier in te dienen met een titel maar zonder inhoud. Je zult het bericht “Inhoud is vereist!” zien. Klik op de FlaskApp-link in de navigatiebalk om terug te keren naar de indexpagina, klik dan op de Terug-knop om terug te keren naar de Create-pagina. Je zult zien dat het inhoudsbericht nog steeds aanwezig is. Dit werkt alleen als je op de Terug-knop klikt, omdat het de vorige aanvraag opslaat. Klikken op de Create-link in de navigatiebalk zal een nieuwe aanvraag verzenden, die het formulier wist, en als gevolg daarvan zal het geflashede bericht verdwijnen.

Je weet nu hoe je gebruikersinvoer kunt ontvangen, hoe je deze kunt valideren en hoe je deze aan een gegevensbron kunt toevoegen.

Opmerking:
De berichten die je toevoegt aan de messages lijst zullen verdwijnen wanneer de server wordt gestopt, omdat Python-lijsten alleen in het geheugen worden opgeslagen, om je berichten permanent op te slaan, zul je een database zoals SQLite moeten gebruiken. Bekijk Hoe de sqlite3-module in Python 3 te gebruiken om te leren hoe je SQLite met Python kunt gebruiken.

Conclusie

Je hebt een Flask-applicatie gemaakt waar gebruikers berichten aan een lijst van berichten kunnen toevoegen die op de indexpagina worden weergegeven. Je hebt een webformulier gemaakt, de gegevens die de gebruiker via het formulier verstuurt verwerkt en deze toegevoegd aan je berichtenlijst. Je hebt ook geflashede berichten gebruikt om de gebruiker te informeren wanneer ze ongeldige gegevens indienen.

Als je meer wilt lezen over Flask, bekijk dan de andere tutorials in de Flask serie.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-web-forms-in-a-flask-application