Ga naar inhoud

Flask en Forms - Form Fields

Validators

Het mooie aan het werken met formulieren is hier dat voor elk mogelijk HTML-formulierveld een bijbehorende wtforms-klasse bestaat die geïmporteerd kan worden. Deze klasse heeft ook validators die op gemakkelijke wijze ingevoegd kunnen worden. Validators kunnen ingezet worden om controles uitvoeren op de formuliergegevens, zoals bijvoorbeeld een controle of een verplicht veld inderdaad een waarde gekregen heeft.

In deze paragraaf is er ook aandacht voor de wijze waarop een sessieobject van Flask ingeschakeld kan worden om de informatie in het formulier op te halen en door te geven aan een template. In een volgende deel wordt aandacht besteed hoe de gegevens in een database opgeslagen kunnen worden.

Voorbeeld

We gaan weer verder met een voorbeeld. Voor het volgende uitgewerkte voorbeeld zijn drie bestanden nodig, een Python-file: form_fields.py en twee HTML-bestanden, home1.html en bedankt.html.

Python gedeelte

Uiteraard wordt begonnen met de Python-file. Het begin is weer meer van hetzelfde, nu alleen met wat uitbreidingen.

from flask import Flask, render_template, session, redirect, url_for, session
from flask_wtf import FlaskForm
from wtforms import (StringField, BooleanField, DateTimeField,
                                  RadioField, SelectField, TextField,
                                  TextAreaField, SubmitField)
from wtforms.validators import DataRequired

app = Flask(__name__)
app.config['SECRET_KEY'] = 'mijngeheimesleutel'

Er worden een aantal extra elementen geïmporteerd van Flask, die zo nader uitgelegd worden. De velden die op het formulier voor gaan komen, worden als bekend verondersteld.

Van de validators wordt de klasse DataRequired opgehaald. Er zijn er nog veel meer, bijvoorbeeld email: een klasse die controleert of een ingevuld e-mailadres aan de eisen voldoet, met punt, extensie en @.

Vervolgens wordt de applicatie en de geheime sleutel gecreëerd.

InfoForm

Volgende stap is weer het opzetten van het formulier:

class InfoForm(FlaskForm):

    naam = StringField('Wat is je naam?',validators=[DataRequired()])
    vrouw  = BooleanField("Ben je een vrouw?")
    instrument = RadioField('Welk instrument wil je leren bespelen?',   choices=[('ins_een','Gitaar'),('ins_twee','Drums')])
    plaats = SelectField(u'Welke locatie heeft de voorkeur?',
             choices=[('as', 'Assen'), ('dr', 'Drachten'), ('gr', 'Groningen')])
    feedback = TextAreaField()
    submit = SubmitField('Verzend')

Dit formulier bevat wat meer velden dan het vorige. De HTML-kennis moet voldoende zijn om deze code te kunnen begrijpen.

De naam is een verplicht veld, en voor ieder instrument en plaats is een tuple aangemaakt. De eerste waarde wordt in de code gebruikt terwijl de tweede waarde steeds zichtbaar is op het formulier.

View functies

Daarna is het de beurt voor de viewfuncties. Als eerste het formulier.

@app.route('/', methods=['GET', 'POST'])
def index():

    form = InfoForm()
    if form.validate_on_submit():

        session['naam'] = form.naam.data
        session['vrouw'] = form.vrouw.data
        session['instrument'] = form.instrument.data
        session['plaats'] = form.plaats.data
        session['feedback'] = form.feedback.data

        return redirect(url_for("bedankt"))


    return render_template('home1.html', form=form)

Een paar opmerkingen: Het lijkt erg veel op de code van de vorige paragraaf. Als eerste extra item wordt session gehanteerd.

Een session-tabel is een kortstondige tijdelijke tabel waarin waarden bewaard kunnen worden om aan een andere pagina door te geven. Een mooi voorbeeld hiervan is een overzicht van bestellingen van artikelen op een website. Als een artikel in een winkelmandje beland is, kan het voorkomen dat er nog een artikel aangeschaft gaat worden. Wanneer naar de pagina gesprongen wordt om het tweede artikel nog een keer uitvoerig te bekijken, wordt wanneer er geen sessievariabelen benut worden, het mandje weer geleegd. De gegevens zijn dan niet ergens opgeslagen.

Een tweede opvallend iets is dat er twee return-statements zijn gebruikt. De laatste is nodig om de eerste keer een leeg formulier te tonen.

Het andere return-statement sluist de waarden gelijk door naar de viewfunctie met de naam ‘bedankt’. De ingevoerde gegevens zullen daar getoond worden. Dit is de volgende stap.

@app.route('/bedankt')
def bedankt():

    return render_template('bedankt.html')

Afsluiting python code

En aan het eind het vertrouwde:

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

HTML gedeelte

Nu kunnen de HTML-formulieren ingevuld worden. Als eerste home1.html:

<h1>Welkom bij de enquete van muziekschool Session</h1>
<form  method="POST">
    {{ form.hidden_tag() }}
    {{ form.naam.label }} {{form.naam}}
    <br>
    {{ form.vrouw.label}} {{form.vrouw}}
    <br>
    {{form.instrument.label}}{{form.instrument}}
    <br>
    {{form.plaats.label}}{{form.plaats}}
    <br>
    Nog andere opmerkingen?
    <br>
    {{form.feedback}}
    <br>
    {{ form.submit() }}
</form>
Het lijkt weer veel op het de code van home.html uit de vorige pagina. Bovenaan een welkomsttekst, gevolgd door de openings-FORM-tag. Binnen het formulier is als eerste de geheime sleutel opgenomen waarna de diverse velden worden geïntroduceerd, zoals in de lijst die is vastgelegd in de Python-file bedankt.html.

bedankt.html

Als het formulier is ingevuld en er op de ‘Verzend’-knop is geklikt wordt de inhoud van de velden doorgestuurd naar bedankt.html en daar getoond:

<h1>Bedankt voor de moeite. <br>Dit zijn de ingevulde gegevens:</h1>
<ul>
    <li>Naam: {{ session['naam'] }}</li>
    <li>Geslacht: {{ session['geslacht'] }}</li>
    <li>Instrument: {{ session['instrument'] }}</li>
    <li>Plaats: {{ session['plaats'] }}</li>
    <li>Feedback: {{ session['feedback'] }}</li>
</ul>

Runnen van de applicatie

Tijd voor een test:

de enquete op home1.html Ingevuld:

home1.html met ingevulde enquete

Na een klik op de button: bedankt.html met daarin de ingevulde waarden van de enquete

Afsluiting

Een paar opmerkingen tot slot van deze paragraaf:

Lay-out

De lay-out kan vele malen mooier door er CSS-stijlen aan toe te voegen. Misschien ziet de output er wat vreemd uit, maar alles is precies volgens de opzet verlopen. Het RadioField en het SelectField zijn beide gevuld met tuples. De eerste waarde van iedere tuple wordt na selectie doorgegeven.

In de keuzelijst kan er bijvoorbeeld gekozen worden uit de zichtbare mogelijkheden, Assen, Drachten en Groningen. De corresponderende sleutelvelden zijn 'as', 'dr' en 'gr'. Deze waarden worden doorgeven naar bedankt.html. Dat is met opzet gebeurd om de werking te tonen. Om de gehele plaatsnaam te tonen zou twee keer dezelfde tekenrij in de tuple moeten worden ondergebracht.

Validator test

Om de test op alle items te toetsen wordt nog een poging gedaan de gegevens te tonen, echter zonder een naam in te vullen. Kijken of de validator dit kan onderkennen:

als je geen naam invult werkt het niet

En inderdaad. Een rood kader om het veld om aan te geven dat dit veld voordat het formulier verwerkt kan worden een invulling moet krijgen.