Construire et accéder à la base de données ========================================== .. container:: section :name: define-and-access-the-database .. rubric:: Construire et accéder à la base de données :name: 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 ":ref:`ref-sql`", les slides des deux cours sur le SQL sur Moodle, ou `la documentation de SQL `__. .. container:: section :name: connect-to-the-database .. rubric:: Connexion à la base de données :name: connection-à-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. .. container:: literal-block-wrapper docutils :name: id1 .. container:: code-block-caption ``mobility/db.py`` .. code-block:: python 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. .. container:: section :name: create-the-tables .. rubric:: Création des tables :name: 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: .. container:: literal-block-wrapper docutils :name: id2-create-ville .. container:: code-block-caption ``mobility/schema.sql`` .. code-block:: 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``: .. container:: literal-block-wrapper docutils :name: id3 .. container:: code-block-caption ``mobility/db.py`` .. code-block:: python 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. .. container:: section :name: register-with-the-application .. rubric:: Enregistrement à l’application :name: enregistrement-à-lapplication 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. .. container:: literal-block-wrapper docutils :name: id4 .. container:: code-block-caption ``mobility/db.py`` .. code-block:: python 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. .. container:: literal-block-wrapper docutils :name: id5 .. container:: code-block-caption ``mobility/__init__.py`` .. code-block:: python 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 .. only:: html Continuez en lisant le document `Plans et vues pour les pays `__.