DY

TP09: ORM

Un ORM est une technique de programmation informatique qui crée l'illusion d'une base de données orientée objet à partir d'une base de données relationnelle en définissant des correspondances entre cette base de données et les objets du langage utilisé. On pourrait le désigner par « correspondance entre monde objet et monde relationnel ».

Flask et les ORMs

Flask ne fournit pas d'ORM par défault, il laisse la faculté à l'utilisateur de choisir la librairie qui lui convient.

Découverte de Peewee

Peewee est un (petit) ORM simple. Il a peu de concepts (mais expressifs), ce qui le rend facile à apprendre et intuitif à utiliser. Celui-ci est open source et disponible à cette adresse.

Installation

Comme toujours un simple pipenv install peewee

La base de données

Pour la suite de ce TP nous allons créer la base de données SQLite suivante:

Boardgames Database Scheme
Diagramme UML de la base de données de MeepleStreet
Configuration

Après avoir installé le paquet peewee il suffit de configurer une connexion à notre base de données.

A la racine de votre projet créer un fichier models.py avec le contenu suivant:

from peewee import *

database = SqliteDatabase("boardgames.sqlite3")
Notre premier Model

Nous définissons d'abord une classe BaseModel qui permet de spécifier la connexion à la BDD à tous nos modéles.

class BaseModel(Model):

    class Meta:
        database = database

Puis de créer directement notre classe Boardgame:

class Boardgame(BaseModel):
    name = CharField()
    slug = CharField()
    description = TextField()
    release_date = DateField()
    created_at = DateTimeField(default=datetime.datetime.now)

Voilà ! Notre model est créé, à nous de l'utiliser !

Création de la base

Avant de commencer à requêter sur notre base, il convient de la .. créer !

Pour ce faire nous allons créer deux fonctions dans notre fichier models.py, l'une pour créer les tables et l'autre pour les détruire:

def create_tables():
    with database:
        database.create_tables([Boardgame, ])


def drop_tables():
    with database:
        database.drop_tables([Boardgame, ])

Enfin nous allons créer les commandes python associer pour créer/détruire les tables au sein du fichier app.py à la fin du fichier ajouter les lignes:

@app.cli.command()
def initdb():
    """Create database"""
    create_tables()
    click.echo('Initialized the database')

@app.cli.command()
def dropdb():
    """Drop database tables"""
    drop_tables()
    click.echo('Dropped tables from database')

Il suffit d'appeller ces commandes dans notre shell:

$ flask initdb
$ flask dropdb
Création de données

Nous pourrions écrire des données à la main pour remplir notre base de données mais cela serait long et ennuyeux, nous allons donc utiliser la puissance de l'ORM et une librairie de création de fausses données pour créer différents enregistrements.

Faker

Faker est un paquet Python qui génère de fausses données. Que vous deviez amorcer votre base de données, créer de beaux documents XML, compléter votre persistance pour la soumettre à un test de résistance, ou anonymiser des données provenant d'un service en production, Faker est fait pour vous.

Comme d'habitude on installe le paquet faker via pipenv install faker. Et le paquet awesome-slugify également.

Puis au sein de notre fichier app.py nous allons créer la fonction suivante:

@app.cli.command()
def fakedata():
    from faker import Faker
    from slugify import slugify
    fake = Faker()
    for pk in range(0, 42):
        name = fake.company()
        Boardgame.create(name=name,
                         slug=slugify(name, to_lower=True)
                         description=fake.catch_phrase(),
                         release_date=fake.date())

Puis pour lancer la commande:

$ flask fakedata
Requête via un Model

Pour plus d'informations sur la manière d'écrire des requêtes, je vous invite à vous rendre à cette page de la documentation.

Dans le fichier app.py nous allons créer une route pour afficher l'ensemble des jeux de plateaux au sein d'un fichier de templating boardgames.html.

Voici le code permettant de récupérer l'ensemble des jeux présent en base:

Boardgame.select()

Cette ligne permet de récupérer tout les jeux présent en bases. A vous maintenant d'itérer sur la liste retourner afin d'obtenir une liste des jeux au sein de votre template.

Associations

Nous allons créer la classe python qui correspond à notre table Category puis définir la clé étrangère entre Boardgame et Category:

class Category(BaseModel):
    name = CharField()
    slug = CharField()
    created_at = DateTimeField(default=datetime.datetime.now)


class Boardgame(BaseModel):
    name = CharField()
    slug = CharField()
    description = TextField()
    release_date = DateField()
    created_at = DateTimeField(default=datetime.datetime.now)
    category = ForeignKeyField(Category, backref="boardgames")

N'oubliez pas d'ajouter dans les fonctions de création et de suppression des tables la classe Category.

Puis nous allons mettre à jour notre générateur de données:

@app.cli.command()
def fakedata():
    from faker import Faker
    fake = Faker()

    for pk in range(0, 5):
        name = fake.company()
        Category.create(name=name,
                        slug=slugify(name, to_lower=True))

    for category in Category.select():
        for pk in range(0, 4):
        name = fake.company()
        Boardgame.create(name=name,
                         slug=slugify(name, to_lower=True)
                         description=fake.catch_phrase(),
                         release_date=fake.date(),
                         category=category)

Ainsi nous pouvons obtenir le nom de la catégorie d'un jeux via:

boardgame.category.name

Ou encore la liste des jeux d'une catégorie via:

category.boardgames

À vous de jouer

  1. Créer une route pour afficher l'ensemble des jeux avec leur catégorie;
  2. Créer une route pour afficher l'ensemble des catégorie et les jeux associés;
  3. Créer une vue pour afficher uniquement les informations d'un seul jeux en prenant en paramètre (slug) le slug du jeux cf la partie sur le requêtage de la documentation.

Conclusion

Nous venons de voir que manipuler une base de données est extrèmement simple avec les bons outils, je vous invite donc à lire la documentation de Peewee notamment sur la partie Querying.