Faire des sondages avec flask et ethercalc
NOTE PRÉLIMINAIRE Les commandes de ce tutorial sont données pour une machine Linux récente. Suivant votre plateforme, vous devrez y apporter quelques adaptations. Notamment, vous devrez peut-être remplacer la commande python par python3, ou py, ou py -3 ou…
Par contre le code python lui-même devrait bien entendu rester inchangé.
Installer uv
Dans ce tutoriel nous allons utiliser uv pour gérer les dépendances.
Suivre les instructions d’installation du site officiel de uv.
Installer flask
~$ mkdir polls
~$ cd polls
~/polls$ uv init
Cela va créer un fichier pyproject.toml, un .python-version, un README.md ainsi qu’un main.py (que nous n’utiliserons pas, vous pouvez le supprimer). Ajoutons maintenant une dépendance à flask:
~/polls$ uv add flask
Le fichier pyproject.toml devrait contenir une description de votre projet avec ses dépendances:
~/polls$ cat pyroject.toml
[project]
name = "polls"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = [
"flask>=3.1.3",
]
uv a aussi créé un fichier uv.lock qui contient une description précise de toutes les dépendances installées avec leur version. Versionnez ce fichier avec le reste, cela vous permettra de reproduire l’environnement de manière fiable!
Hello World avec Flask
Créez un fichier polls.py avec un programme Flask minimal:
from flask import Flask
app = Flask(__name__)
@app.get('/')
def hello():
return 'Hello World!'
C’est le moment de tester:
~/polls$ uv run flask --app polls run --debug
S’il n’y a pas d’erreur, rendez-vous sur http://localhost:5000/ où vous devriez être accueilli par un sympathique Hello World!
Remarque Dans de nombreux tutos flask un peu anciens, vous verrez @app.route() au lieu du @app.get() ci-dessus. app.get(<path>) est au fait un alias vers app.route(<path>, methods=['GET']) (ajouté dans Flask 2.0). Cela permet de rendre les choses plus concises quand on veut utiliser d’autres méthodes http (voir ci-dessous pour POST).
Créer une feuille ethercalc…
Évidemment le mieux serait d’héberger Ethercalc nous-même, mais pour ce rapide tuto nous utiliserons une instance hébergée ailleurs. L’application est disponible sur différents serveurs, mais ils ne sont pas tous disponibles tout le temps, et certains ne tiennent pas bien la charge. Choisissez l’un des serveurs ci-dessous (pas tous le même!) et changez-en si vous rencontrez des problèmes.
- https://ethercalc.net/
- https://calc.ti-nuage.fr/
- https://ethercalc.nomagic.uk/
- https://tableur.kaz.bzh/
- https://calc.domainepublic.net/
Sur l’un de ces serveurs, créez une nouvelle feuille et:
- Prenez note de l’ID généré car nous en aurons besoin par la suite (et c’est la seule manière de retrouver votre feuille…).
- Dans la cellule A1, entrez le titre de votre sondage.
- Dans les cellules B2, C2, E2, … entrez les options de votre sondage. Pour plus de clareté, vous pouvez noter “Nom” en A2 (le nom des personnes ayant voté s’inscrira dans cette colonne).

Nous allons maintenant changer la page d’accueil: remplacez la méthode hello() par
@app.get('/')
def poll_list():
# Adaptez l'ID à la feuille que vous avez créée ci-dessus!
return render_template('home.html', poll_id='zxya1mcjhwkv')
Pour que cela fonctionne, il faudra
- compléter la ligne d’importation en haut de fichier
from flask import Flask, render_template
- créer un répertoire
templateset - y ajouter un
home.html. Pour le moment nous ne gérerons qu’un seul sondage:
<h1>Application de sondage</h1>
<p>Voir le <a href="/{{poll_id}}">sondage</a></p>
Testez: http://localhost:5000/ devrait maintenant vous donner un lien vers votre sondage… mais naturellement un lien brisé!
On va donc corriger ça. D’abord on se donne un moyen de récupérer les données du sondage. Vers le haut du fichier, on ajoute une définition de “constante”:
# Bien entendu, adaptez l'URL au serveur choisi!
ETHERCALC_URL = 'https://ethercalc.net'
puis on définit la fonction suivante:
def get_poll_as_csv(id):
url = f'{ETHERCALC_URL}/_/{id}/csv'
answer = urlopen(url)
content = answer.read().decode(answer.headers.get_content_charset()).splitlines()
reader = csv.reader(content)
return list(reader)
… Sans oublier d’ajouter les imports correspondants en haut du fichier:
from urllib.request import urlopen
import csv
Ensuite on définit la route:
@app.get("/<id>")
def display_poll(id):
sheet = get_poll_as_csv(id)
# First line has title
title = sheet.pop(0)[0]
# Second line is dummy value, then options:
options = sheet.pop(0)[1:]
return render_template("poll.html", **locals())
… et enfin le template poll.html
<h1>{{title}}</h1>
<ul>
{% for o in options %}
<li>{{o}}</li>
{% endfor %}
</ul>
Vous devriez maintenant pouvoir aller sur la page du sondage et voir les options possibles.
Vers une mise en place du vote…
Nous avons réussi à aller chercher des informations dans un tableur, il nous reste à les modifier…
Juste sous le <h1> de poll.html, ajoutez
<form action="" method="post">
<label for="id_who">Your Name</label>
<input type="text" name="who" id="id_who" />
<input type="submit" class="button" value="Vote!"/>
</form>
On se donne le moyen d’ajouter des données à notre feuille via l’API d’ethercalc:
def add_row_to_poll(id, data):
url = f'{ETHERCALC_URL}/_/{id}'
headers = {
'Content-Type': 'text/csv'
}
new_row = ','.join(f'"{s}"' for s in data)+','
request = Request(url,
headers=headers,
data=new_row.encode('utf-8'))
urlopen(request)
On complète l’import d’urllib:
from urllib.request import urlopen, Request
Et enfin, on ajoute
@app.post('/<id>')
def vote(id):
voter = request.form['who']
add_row_to_poll(id, [voter])
return redirect(url_for('display_poll', id=id))
(sans oublier d’importer request, redirect et url_for du module flask!)
On devrait maintenant pouvoir “voter”: le nom du participant est ajouté au tableur… mais le participant n’a pas encore l’occasion de donner son avis!
À vous de jouer!
En vous aidant de la documentation de flask, de celle de Jinja, et au besoin de la doc de l’API d’ethercalc effectuez les tâches suivantes:
- Ajoutez la possibilité de voter pour une ou plusieurs options du sondage: cela ajoutera des ‘x’ dans les cases correspondantes du tableur.
- Lors de l’affichage du sondage, ajoutez un affichage des votes précédents sous forme de tableau.
- Modifiez la page d’accueil pour qu’elle contienne un formulaire qui permet de créer un nouveau sondage avec un titre et des options donnés.
Et si vous avez le temps…
Ajoutez quelques améliorations parmi les idées ci-dessous:
- Nos templates sont pour l’instant impossibles à maintenir… créez un
templates/base.htmlqui définit la structure globale des pages et un certain nombre deblock’s qui seront écrasés dans les templateshome.htmletpoll.html(principe DRY) - Que c’est moche tout ça… Stylez le tout avec un bon coup de CSS!
- Ajoutez un message de remerciement après le vote avec flash.
- Ajoutez des statistiques en tête de la page d’un sondage (N personnes ont voté, Le choix le plus populaire est X avec Y% des suffrages, …)
- Vérifiez la validité d’un vote avant de mettre à jour le tableur (p.ex. au moins une option a été sélectionnée) et au besoin affichez un message d’erreur dans le formulaire.
- Ajoutez des statistiques graphiques, par exemple avec pygal
- Stockez la liste des sondages créés par l’application dans une feuille “master” et ajoutez la possibilité de lister, d’administrer, détruire des sondages…
- Lorsque quelqu’un vote, envoyez un mail à l’administrateur pour l’informer
- Commandez automatiquement les bières chez le brasseur artisanal du coin en fonction du nombre prévu de participants à une séance ;-)
- …
Pour aller plus loin…
-
Détails sur flask & ses outils
- How to make a Flask blog in one hour or less
- How to use Python and Flask to build a web app — an in-depth tutorial
- Primer on Jinja Templating
- The Flask Mega-Tutorial
- Things which aren’t magic - Flask and @app.route
- Video Streaming with Flask
- Synchronize clients of a Flask application with websockets
- Getting Every Microsecond Out of uWSGI
- Debugging a Python Flask Application in a Container with Docker Compose
- Beaucoup d’autres liens sur Awesome Flask
-
Quelques tuyaux pour vous perfectionner en python: