Faire des sondages avec Flask et les Google Docs

Prérequis

Hello World avec Flask

Commencez par activer l'environnement virtuel où vous avez installé Flask:

$ source tuto-flask/bin/activate

(ou tuto-flask\scripts\activate sous Windows)

Ensuite créez un répertoire pour le projet:

(tuto-flask) ~ $ cd [...]/Projects
(tuto-flask) ~/.../Projects$ mkdir SpreadPoll
(tuto-flask) ~/.../SpreadPoll$ cd SpreadPoll

Dans ce répertoire, créez un fichier SpreadPoll.py avec le Hello World de la documentation Flask (en y rajoutant le shebang et l'encodage pour la bonne forme, et en activant le débogueur):

#!/usr/bin/python
# coding: utf-8

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run(debug=True) # désactiver le debug en production!!!

C'est le moment de tester:

(tuto-flask) ~/.../SpreadPoll$ python SpreadPoll.py

S'il n'y a pas d'erreur, rendez-vous sur http://localhost:5000/ où vous devriez être accueilli par un sympathique Hello World!

Si ça marche, c'est le moment de mettre en route le suivi des modifications:

(tuto-flask) ~/.../SpreadPoll$ git init
Initialized empty Git repository in [...]/SpreadPoll/.git/
(tuto-flask) ~/.../SpreadPoll$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   SpreadPoll.py
nothing added to commit but untracked files present (use "git add" to track)

Si d'autres fichiers que SpreadPoll.py apparaissent (p. ex. sauvegardes automatiques, etc) il faudra les exclure du suivi de version en créant un fichier .gitignore contenant quelque chose comme:

# toujours une bonne idée dans les projets python
*.pyc
# Si nécessaire, des choses comme
*~
*.bak

On réssaie:

(tuto-flask) ~/.../SpreadPoll$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#   .gitignore
#   SpreadPoll.py
nothing added to commit but untracked files present (use "git add" to track)

Cette fois-ci c'est bon! On ajoute tous les fichiers et on "committe":

(tuto-flask) ~/.../SpreadPoll$ git add .
(tuto-flask) ~/.../SpreadPoll$ git commit -m "Mise en route du projet SpreadPoll."
[master (root-commit) fec9467] Mise en route du projet SpreadPoll.
 2 files changed, 18 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 SpreadPoll.py

Simplifier la reprise ou le déployement du projet

(tuto-flask) ~/.../SpreadPoll$ pip freeze > requirements.txt
(tuto-flask) ~/.../SpreadPoll$ cat requirements.txt
Flask==0.10.1
itsdangerous==0.24
Jinja2==2.7.3
MarkupSafe==0.23
Werkzeug==0.10.4
(tuto-flask) ~/.../SpreadPoll$ git add requirements.txt
(tuto-flask) ~/.../SpreadPoll$ git commit -a -m "Ajouté un fichier de requirements."

Dorénavant, il suffira de faire un pip install -r requirements.txt pour reconstituer l'ensemble des bibliothèques dans les bonnes versions!

Attention! Ne pas oublier de mettre ce fichier à jour à chaque nouvelle installation ou mise à jour d'une bibliothèque!

On ajoute les Google Docs...

Connectez-vous à votre compte Google et créez un Spreadsheet nommé Polls. Créez une ou deux feuilles en suivant ces conventions:

Exemple de google doc

Pour communiquer avec les Google Spreadsheets nous utiliserons gspread:

(tuto-flask) ~/.../SpreadPoll$ pip install gspread
[...]
(tuto-flask) ~/.../SpreadPoll$ pip freeze > requirements.txt

Nous aurons besoin d'un login Google, mais bien entendu il ne doit pas être inclus dans le contrôle de version. Créez donc un fichier google_account.py:

google_user = <votre username google>
google_pass = <votre mot de passe>

Et ajoutez ce fichier à .gitignore.

Remarques:

Retour dans SpreadPoll.py. Modifiez le début du fichier pour qu'il ressemble à ça:

[...]

import sys
from flask import Flask
import gspread
from google_account import google_user, google_pass

# Connect to google docs and find the spreadsheet named "Polls"

try:
    gc = gspread.login(google_user, google_pass)
except gspread.exceptions.AuthenticationError:
    print "Cannot log in"
    sys.exit(1)

try:
    spreadsheet = gc.open("Polls")
except gspread.exceptions.SpreadsheetNotFound:
    print "Cannot find spreadsheet"
    sys.exit(1)

# Create the flask app

app = Flask(__name__)

[...]

Relancez l'application. Normalement, tout devrait se comporter comme avant (Hello World! sur http://localhost:5000/), mais avec un délai au démarrage: on se connecte au tableur, mais on n'en fait rien du tout!

En cas de problème

Commençons par changer la page d'accueil: remplacez la méthode hello_world() par

@app.route('/')
def poll_list():
    worksheets_list = spreadsheet.worksheets()
    return render_template('home.html', polls=worksheets_list)

Pour que cela fonctionne, il faudra

Testez: http://localhost:5000/ devrait maintenant vous donner une liste des sondages disponibles!

Par contre, les liens sont tous brisés... on va donc corriger ça:

@app.route('/<poll_slug>')
def display_poll(poll_slug):
    try:
        poll = spreadsheet.worksheet(poll_slug)
    except gspread.exceptions.WorksheetNotFound:
        return "Sorry, no poll at that url", 404

    options = poll.row_values(1)
    title = options.pop(0)

    return render_template('poll.html', **locals())

... et dans le fichier poll.html

<h1>{{title}}</h1>

<ul>
    {% for o in options %}
        <li>{{o}}</li>
    {% endfor %}
</ul>

Vous devriez maintenant pouvoir aller sur la page d'un 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>

Modifiez ensuite la déclaration de display_poll:

@app.route('/<poll_slug>', methods=['GET'])
def display_poll(poll_slug):
    [...]

Enfin, ajoutez

@app.route('/<poll_slug>', methods=['POST'])
def vote(poll_slug):
    try:
        poll = spreadsheet.worksheet(poll_slug)
    except gspread.exceptions.WorksheetNotFound:
        return "Sorry, no poll at that url", 404

    voter = request.form['who']

    nb_voters = len(poll.col_values(1))

    poll.update_cell(nb_voters+1, 1, voter)

    return redirect(url_for('display_poll', poll_slug=poll_slug))

(sans oublier d'importer request, redirect et url_for du package flask!)

On devrait maintenant pouvoir "voter": le nom du participant est ajouté au tableur... qui n'a pas encore l'occasion de donner son avis!

Avant d'aller plus loin, ne pas oublier de "comitter":

(tuto-flask) ~/.../SpreadPoll$ git add .
(tuto-flask) ~/.../SpreadPoll$ git commit -a -m "Lien vers les google docs et ajout de templates".

À vous de jouer!

En vous aidant de la documentation de flask, de celle de gspread et de celle de Jinja2, effectuez les tâches suivantes:

Et si vous avez le temps...

Ajoutez quelques améliorations parmi les idées ci-dessous:

Pour aller plus loin...