Le modèle MVC

Bien qu'il soit possible de contenir tout le site dans un seul fichier python, cela n'est pas recommandable. Le fichier deviendra vite très gros, et il sera difficile de modifier une partie de l'application.

Le site suivant est fonctionnel, mais tout est mélangé. La gestion du HTML dans une seule chaîne de caractère est particulièrement sujette à l'introduction d'erreurs.

from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
    """
    retourne le contenu de la page index.html
    """
    return '<!doctype html><head><title>Acceuil</title></head><body>' \
        'Cliquez ici pour aller sur page : <a href="page.html">lien</a>.</body></html>'

@app.route('/page.html')
def page():
    """
    retourne le contenu de la page page.html
    """
    return '<!doctype html><head><title>Page</title></head><body>Page</body></html>'

Nous allons voir un premier moyen de ségrégation entre deux rôles :

  • la logique de l'application, le code python qui va dans un fichier .py

  • le rendu en HTML, qui va dans une série de fichiers HTML.

Dans le modèle MVC, ou Modèle-Vue-contrôleur, ces deux éléments sont appelés respectivement le contrôleur et la vue. Très vite, vous allez devoir utiliser le troisième rôle : les modèles. Les modèles gèrent les données dynamiques, comme un utilisateur sur lequel le contrôleur va travailler, afin de finalement afficher les données dans la vue. Nous y reviendrons plus tard.

Vue

Dans le modèle MVC abstrait, la vue gère ce qui concerne la structure de la page, entendons ici le HTML. On utilise en général le terme « template » pour désigner les fichiers HTML utilisés pour la vue. Nous avons ici un problème lié au Français, en anglais Template se traduit en Modèle, qui est un autre rôle du MVC. Nous utiliserons donc plutôt le mot anglais Template.

Déplaçons le code HTML de l'index dans un fichier propre, dans template/index.html:

<!doctype html>
<html>
    <head><title>Acceuil</title></head>
    <body>
        Cliquez ici pour aller sur page : <a href="page.html">lien</a>.
    </body>
</html>

Nous allons utiliser la fonction render_template() pour aller chercher le contenu du fichier index.html et l'afficher:

from flask import Flask
from flask import render_template
app = Flask(__name__)

@app.route('/')
def index():
    """
    retourne le contenu de la page index.html
    """
    return render_template('index.html')

@app.route('/page.html')
def page():
    """
    retourne le contenu de la page page.html
    """
    return  render_template('page.html')

Contrôleur

Le contrôleur est la logique de l'application. Dans l'exemple utilisé ci-dessus, les deux pages sont des contrôlleurs. Il est possible de les séparer dans des fichiers distincts, ce qui est souhaitable en utilisant un blueprint. Les détails du blueprint seront vu au premier TP.

Le fichier suivant montre un contrôleur qui serait responsable de /page.html, mais dans un fichier séparé page.py:

from flask import Blueprint
from flask import render_template

bp = Blueprint('page', __name__)

@bp.route('/page.html')
def index():
    return render_template('page.html')

Les blueprints permettent de déléguer des contrôleurs.

Modèle

Ce sont les données, par exemple “User” qui contient “firstName”, “lastName”, etc. On parle aussi parfois d'objets pour des raisons que vous verrez plus tard, dans les cours de programmation orientée objet.

En général, ils sont stockés et retournés dans/depuis une base de données, nous verrons cela au Chapitre 7 : Les bases de donnée.

Le fichier suivant est créé dans un dossier models, c'est une convention pour les modèles. Par exemple models/user.py.

class User:
    def __init__(self, firstName, lastName):
        self.firstName = firstName
        self.lastName = lastName

    def get_complete_name(self):
        return self.firstName + " " + self.lastName

À ce stade, la classe User est très simple et ne contient pas vraiment de logique si ce n'est get_complete_name().

Interaction

En fonction d’une entrée (comme la requête GET vers /page), Flask va choisir un contrôleur. Le contrôleur va éventuellement utiliser une série de Modèles pour remplir les vues et les renvoyer à l’utilisateur.

Ce concept sera mis en pratique dans le TP2, qui est accessible ici: Chapitre 4 : Travaux Pratiques #2 : Un site Flask sans base de données.