Construire et accéder à la base de données¶
Construire et accéder à la base de données
L’application va utiliser une base de données SQLite pour stocker les informations liées au projet. Python intègre un support pour SQLite dans le module sqlite3.
SQLite est intéressant, car il peut s’utiliser sans l’installation d’un serveur de base de données séparé et il est directement intégré à Python. Cependant, si plusieurs accès en écriture à la base de données se font en même temps, l’application va ralentir, parce que ceux-ci doivent être séquentiels. Pour de petites applications, ce n’est pas important. Si votre application prend de l’ampleur et nécessite beaucoup d’écritures, vous devrez peut-être passer à une autre base de données.
Ce tutoriel ne rentre pas dans les détails du langage SQL. N'hésitez pas à retourner lire le "Les bases de données SQL", les slides des deux cours sur le SQL sur Moodle, ou la documentation de SQL.
Connexion à la base de données
La première chose à faire pour travailler avec une base de données SQLite (et la plupart des autres librairies Python de gestion de bases de données) est de créer une connexion avec la base de données. Toutes les requêtes et les opérations se font en utilisant la connexion qui est fermée lorsque le travail est terminé.
Dans une application web, cette connexion est généralement associée à la requête. Elle est créée pendant le traitement de la requête et fermée avant l’envoi de la réponse.
mobility/db.py
import sqlite3
from flask import current_app, g
def get_db():
if 'db' not in g:
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types=sqlite3.PARSE_DECLTYPES
)
g.db.row_factory = sqlite3.Row
return g.db
def close_db(e=None):
db = g.pop('db', None)
if db is not None:
db.close()
g est un objet spécial
qui est unique pour chaque requête. Il est utilisé
pour stocker des données qui pourraient être accédées
par plusieurs fonctions durant le traitement de la
requête. La connexion est conservée et réutilisée si
get_db
est appelé une deuxième fois dans le
traitement de la même requête.
current_app
est un autre objet spécial qui pointe vers
l’application Flask qui traite la requête. Comme vous
avez utilisé une usine à application, il n’y a pas
d’objet application en écrivant la suite de votre
code. get_db
sera appelée lorsque l’application a
été créée et qu’elle traite une requête. De cette
façon,
current_app
peut être utilisé.
sqlite3.connect()
crée une connexion avec le fichier correspondant au
paramètre de configuration DATABASE
. Il n’est pas
nécessaire que ce fichier existe. Il sera créé plus
tard lors de l’initialisation de la base de données.
Le paramètre sqlite3.Row indique que la connexion doit retourner des lignes qui sont équivalentes à des dictionnaires Python. Cela permet d’accéder aux colonnes en indiquant leur nom.
close_db
vérifie si une connexion a été créée en
regardant si g.db
a été initialisé. Si la
connexion existe, elle est fermée. Vous apprendrez plus
tard à votre application d’utiliser la fonction
close_db
depuis l’usine à applications de façon à
l’appeler automatiquement après le traitement de
chaque requête.
Création des tables
Dans SQLite, les données sont stockées dans des
tables et des colonnes. Elles doivent être créées
avant que vous ne puissiez stocker et récupérer des
données dans la base de données. Pour votre projet, la base de données, vous sera fournie sur Moodle, vous ne devrez donc pas créer de table vous-même. Nous pouvons créer une base de données contenant une table country
en utilisant les commandes SQL
ci-dessous:
mobility/schema.sql
DROP TABLE IF EXISTS country;
CREATE TABLE country(iso_country TEXT PRIMARY KEY, name TEXT);
INSERT INTO country(iso_country,name) VALUES("FI", "FINLAND");
Vous pouvez voir qu'en plus de créer la table country
, le code ci-dessus insère également un pays (la Finlande).
Vous pouvez exécuter ces commandes SQL en les
intégrant comme ci-dessous dans le fichier db.py
:
mobility/db.py
def get_db():
"""Returns the database connection. Create the connection if needed.
Returns:
db: The db connection to be used for SQL functions
"""
# g is the shorthand for "globals" and allows registering available in the whole Flask app
if 'db' not in g:
# If it's not there, let's create the db connection
g.db = sqlite3.connect(
current_app.config['DATABASE'],
detect_types=sqlite3.PARSE_DECLTYPES
)
print(current_app.config['DATABASE'])
# Instead of getting "tuple" out of queries, we'll get dictionaries of column->value
g.db.row_factory = sqlite3.Row
return g.db
def close_db(e=None):
"""Close the database
Args:
e: unused
"""
db = g.pop('db', None)
if db is not None:
db.close()
def init_db():
db = get_db()
# Not necessary for the project
with current_app.open_resource('schema.sql') as f:
db.executescript(f.read().decode('utf8'))
def init_app(app):
app.teardown_appcontext(close_db)
open_resource()
ouvre un fichier qui est relatif au package
mobility
. L’utilisation d’un chemin relatif est
intéressant, car vous ne saurez pas nécessairement quel
sera ce répertoire lorsque vous mettrez votre
application en production. get_db
retourne une
connexion à la base de données, qui est utilisée pour
exécuter les commandes lues dans le fichier passé en
argument.
Enregistrement à l’application
La fonction close_db
doit être enregistrée dans l’instance de
l’application. Sinon, elle ne peut pas être
utilisée par l’application.
mobility/db.py
def init_app(app):
app.teardown_appcontext(close_db)
app.teardown_appcontext() demande à Flask d’appeler cette fonction lorsqu’elle libère les ressources associées à une requête après avoir retourné la réponse.
Vous devez importer et appeler cette fonction depuis l’usine à applications. Placez le nouveau code à la fin de la fonction contenant l’usine à applications et juste avant de retourner l’application.
Si ce n'est pas fait, définissez également la variable DATABASE
ainsi que le code permettant de créer le répertoire instance.
mobility/__init__.py
def create_app():
app = ...
# existing code omitted
app.config.from_mapping(
SECRET_KEY='dev',
DATABASE=os.path.join(app.instance_path, 'db.sqlite')
)
# existing code omitted
# ensure the instance folder exists
try:
os.makedirs(app.instance_path)
except OSError:
pass
from . import db
db.init_app(app)
with app.app_context():
db.init_db()
return app
Continuez en lisant le document Plans et vues pour les pays.