Form di contatto

Flask ci mette a disposizione delle istruzioni per gestire un form di contatto e le relative richieste di dati.

Ogni volta che un client comunica con un server lo fa attraverso una request(richiesta).

Per impostazione predefinita i ruote con Flask supportano solo le richieste GET.

Si tratta di richieste di dati come ad esempio cosa visualizzare in una finestra del browser. Quando si invia un form attraverso un sito web, i dati del form vengono inviati come richiesta POST. Questo tipo di richiesta vuole aggiungere dati. I route possono gestire le richieste POST se è specificato nell'argomento metod del decoratore route().

@app.route("/", methods=["GET", "POST"])

Flask fornisce l'accesso ai dati della richiesta attraverso l'oggetto request. L'importazione dell'oggetto request ti permette di accedere a tutto ciò che riguarda le richieste alla tua app, compresi i dati del form e il metodo di richiesta come GET o POST.

from flask import request

Quando i dati vengono inviati tramite un form, è possibile accedervi utilizzando l'attributo form dell'oggetto request. L'attributo form è un dictionary con i nomi dei campi del form come chiavi e i dati associati come valori.

Per esempio, se un input di testo avesse il nome "testo", allora l'accesso ai dati sarebbe simile a questo:

campo_di_testo = request.form["testo"]

Selezione del percorso

Man mano che i siti web diventano più grandi la loro struttura di file diventa più complessa, i percorsi dei route con Flask possono cambiare. In questo caso i percorsi che sono codificati in modo rigido negli elementi di navigazione come i collegamenti ipertestuali e nei form possono "rompersi".

Flask fa fronte a questo problema con url_for(). La funzione url_for() prende il nome della funzione di un route come argomento e restituisce il percorso URL associato.

I due link sotto sono uguali, scritti in modo diverso pa portano allo stesso risultato...

<a href="/">Home</a>

<a href="{{ url_for('index') }}">Home</a>

Scomponendo la seconda riga del codice di cui sopra, possiamo vedere alcune cose:

  • url_for() è all'interno di un delimitatore di espressioni.
  • l'argomento per url_for() è all'interno di singole virgolette.
  • l'intera dichiarazione è all'interno delle doppie virgolette.

Qui è importante usare un tipo di virgolette per l'intera espressione e l'altro tipo di virgolette per l'argomento dell'url_for().

Per passare le variabili dal template all'applicazione, gli argomenti delle parole chiave possono essere aggiunti a url_for(). Essi saranno inviati come argomenti allegati all'URL.

È possibile accedervi nello stesso modo come se fosse stato aggiunto manualmente sul route.

<a href="{{ url_for('mia_pagina', id=1) }}">Prima</a>

Ecco un esempio di seguito in una pagina HTML:

<html>
 <body>
   <div>
     <a href="{{ url_for('index') }}">Home</a>
     <a href="{{ url_for('chi_siamo') }}">Chi siamo?</a>
   </div>
   <h1>Il mio sito web</h1>
 <p>Benvenuto nella mia pagina web!</p>
 {% for id, name in template_esempio.items() %}
   <p>
     <a href="{{ url_for('posts', id=id) }}">{{ nome }}</a>
   </p>
 {% endfor %}
 <form action="/" method="POST">
   <h3>Inserisci un post</h3>
   <p>
     <label for='recipe'>Titolo:</label>
     <input type='text' name='titolo'/>
   </p>
   <p>
     <label for='contenuto'>Contenuto:</label>
     <textarea name='contenuto'></textarea>
   </p>
   <input type='submit' name='invia_post'/>
 </form>
 </body>
</html>

Classe FlaskForm

Flask fornisce un'alternativa ai form web creando una classe di form nell'applicazione, implementando i campi nel template e gestendo i dati di ritorno nell'applicazione.

La classe è FlaskForm e include attributi per ogni campo:

class Mio_Form(FlaskForm):
   mio_campo_testo = StringField("Etichetta_testo")
   mio_campo_invia = SubmitField("Nome_invia")

FlaskForm è una parte di FlaskWTF.

Di seguito è riportata una semplice applicazione Flask con la FlaskForm.

from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField

app = Flask(__name__)

app.config["SECRET_KEY"] = "mio_codicesegreto"

class Mio_Form(FlaskForm):
   my_textfield = StringField("Etichetta_testo")
   my_submit = SubmitField("Nome_invia")

@app.route("/")
def my_route():
   flask_form = Mio_Form()
   return render_template("mio_template", template_form=flask_form)

Qui puoi vedere appliacata anche una nuova linea di codice ovvero: app.config["SECRET_KEY"] = "mio_codicesegreto" . Questa linea di codice è un modo per proteggersi contro la CSRF o la falsificazione delle richieste di informazioni tra i siti (Cross-Site Request Forgery). In poche parole il CSRF è un attacco hacker che veniva utilizzato per ottenere il controllo di un'applicazione web.

Gestione dei dati con FlaskForm

Una volta inviato un form, i dati vengono inviati al server attraverso una richiesta POST. In precedenza hai visto come accedere a questi dati attraverso l'oggetto request fornito da Flask.

Utilizzando la nostra classe FlaskForm, i dati sono ora accessibili attraverso l'istanza form nell'applicazione creata con Flask. Si può accedere direttamente ai dati utilizzando l'attributo data associato ad ogni campo della classe.

dati_form = flask_form.mio_campo_testo.data

Mantenere tutte le informazioni e le funzionalità collegate all'oggetto form ha snellito il processo di creazione del form e di raccolta dei dati.

Ricordati che quando un route gestisce un form è necessario aggiungere il metodo POST al decoratore route().

Di seguito un esempio di gestione di un form:

from flask import Flask, render_template, request
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField

app = Flask(__name__)

app.config["SECRET_KEY"] = "mysecret"

class CommentoForm(FlaskForm):
  commento =  StringField("commento")
  submit = SubmitField("Aggiungi commento")

@app.route("/", methods=["GET", "POST"])
def index():
  return render_template("index.html", template_messaggio=messaggi)

@app.route("/messaggi/<int:id>", methods=["GET", "POST"])
def commento(id):
  commento_form = CommentoForm()
  nuovo_commento = commento_form .commento.data
  messaggi[id].append (nuovo_commento)
  return render_template ("messaggio.html", template_messaggi=messaggi[id])

Convalida dei dati

Per poter inviare un modulo, è prassi comune che alcuni campi di testo obbligatori debbano avere dei dati, tipo il nome o l'email, altri campi devono avere un formato specifico, o che la casella dell'accettazione della privacy deve essere spuntata.

La convalida dei dati, o validazione, è quando i campi del form devono contenere dati o un certo formato di dati per poter procedere con l'invio. Abilitiamo la validazione nella nostra classe  form usando il parametro validator nella definizione dei campi del form.

Validator proviene dal modulo wtform.validators. L'importazione del validator DataRequired() si effettua in questo modo:

from wtforms.validators import DataRequired

Il validatore DataRequired() richiede semplicemente che un campo abbia qualcosa dentro prima che il form venga inviato. La notifica all'utente che i dati sono richiesti viene gestita automaticamente.

Inserendolo nell'esempio precedente:

...
class CommentoForm(FlaskForm):
  commento =  StringField("commento", validators=[DataRequired()]))
  submit = SubmitField("Add commento")
...

Altri campi del form

TextAreaField

Il TextAreaField è un campo di testo che supporta l'inserimento di più righe. I dati restituiti da un'istanza di TextAreaField sono una stringa che può includere anche più caratteri di spazi bianchi.

area_testo = TextAreaField("Etichetta")

RadioField

Con l'oggetto RadioField viene creato un gruppo di pulsanti radio. Poiché ci sono più scelte in questo gruppo, la dichiarazione dell'istanza prende un argomento per l'etichetta del gruppo e una moltitudine di argomenti e choices che prende una lista di tuple.

gruppo_radio_scelta = RadioField("Etichetta", choices=[("id1", "Uno"), ("id2","Due"), ("id3","Tre")])

Redirect

Consideriamo il caso in cui creiamo il nostro form in un route, ma dopo l'invio del form vogliamo che l'utente finisca in un'altr routo. redirect() è la migliore opzione per spostarsi da un route all'altro.

redirect("testo_url")

L'utilizzo di questa funzione all'interno di un route ci invierà all'URL specificato. Nel caso di invio di un form, possiamo usare redirect() dopo aver elaborato e salvato i nostri dati all'interno del nostro controllo validate_on_submit().

Per evitare possibili problemi nella stringa che specifica l'URL, possiamo utilizzare url_for() all'interno di redirect(). Questo ci permette di navigare attraverso i route specificando il nome della funzione route invece dell'URL.

redirect(url_for("nuovo_route", _external=True, _scheme='https'))

Gli argomenti chiave _external=True e _scheme='https' assicurano che l'URL a cui reindirizziamo sia un indirizzo HTTPS sicuro e non un indirizzo HTTP insicuro.