Flask avec PostgreSQL : guide pratique
Pourquoi Flask avec PostgreSQL : guide pratique ?
Dans un monde où l'analyse de données et la gestion des informations structurées sont omniprésentes, il est crucial d'avoir une base de données robuste et performante pour stocker et manipuler ces données. PostgreSQL est un système de gestion de bases de données relationnelles très populaire pour sa stabilité, sa puissance et sa flexibilité. Flask, quant à lui, est un framework web Python populaire qui permet d'élaborer des applications web en quelques heures.
Un cas d'usage concret serait une application de gestion de projet où les utilisateurs doivent être capables de créer, modifier et supprimer des tâches, tout en conservant une trace historique des modifications. Cette application nécessiterait une base de données pour stocker les informations sur les projets, les utilisateurs et les tâches.
Prerequis
- Connaissance de Python
- Connaissance de base de Flask (routes, templates, vues)
- Connaissance de PostgreSQL (CRUD operations, migrations)
- Installation d'PostgreSQL
# Ubuntu/Debian sudo apt-get update sudo apt-get install postgresql postgresql-contrib # macOS (avec Homebrew) brew install postgresql
Concepts fondamentaux
Connexion à PostgreSQL avec Flask
Avant de pouvoir interagir avec la base de données, nous devons d'abord établir une connexion. Voici comment le faire avec psycopg2, un pilote PostgreSQL pour Python.
import psycopg2
def get_db_connection():
conn = psycopg2.connect(
host='localhost',
database='mydatabase',
user='myuser',
password='mypassword'
)
return conn
Création d'une base de données et d'une table
Avant de pouvoir utiliser la base de données, nous devons créer une table pour stocker nos données.
## Connexion à la base de données
conn = get_db_connection()
cur = conn.cursor()
## Création de la table
create_table_query = '''
CREATE TABLE IF NOT EXISTS tasks (
id SERIAL PRIMARY KEY,
title VARCHAR(100) NOT NULL,
description TEXT,
completed BOOLEAN DEFAULT False
);
'''
cur.execute(create_table_query)
## Sauvegarde des modifications et fermeture de la connexion
conn.commit()
cur.close()
conn.close()
Insertion de données
Voici comment insérer des données dans la table tasks.
def insert_task(title, description):
conn = get_db_connection()
cur = conn.cursor()
insert_query = 'INSERT INTO tasks (title, description) VALUES (%s, %s)'
cur.execute(insert_query, (title, description))
conn.commit()
cur.close()
conn.close()
## Exemple d'utilisation
insert_task('Task 1', 'Description of task 1')
Lecture des données
Pour lire les données de la base de données, nous utilisons une requête SQL SELECT.
def get_tasks():
conn = get_db_connection()
cur = conn.cursor()
select_query = 'SELECT * FROM tasks'
cur.execute(select_query)
tasks = cur.fetchall()
cur.close()
conn.close()
return tasks
## Exemple d'utilisation
tasks = get_tasks()
for task in tasks:
print(task)
Mise à jour des données
Pour mettre à jour les données, nous utilisons une requête SQL UPDATE.
def update_task(id, completed):
conn = get_db_connection()
cur = conn.cursor()
update_query = 'UPDATE tasks SET completed = %s WHERE id = %s'
cur.execute(update_query, (completed, id))
conn.commit()
cur.close()
conn.close()
## Exemple d'utilisation
update_task(1, True)
Suppression des données
Pour supprimer une entrée dans la base de données, nous utilisons une requête SQL DELETE.
def delete_task(id):
conn = get_db_connection()
cur = conn.cursor()
delete_query = 'DELETE FROM tasks WHERE id = %s'
cur.execute(delete_query, (id,))
conn.commit()
cur.close()
conn.close()
## Exemple d'utilisation
delete_task(1)
Mise en pratique : projet fil rouge
Pour mettre en pratique les concepts appris, nous allons créer une application simple de gestion des tâches. Cette application aura les fonctionnalités suivantes :
- Ajouter une nouvelle tâche.
- Afficher la liste des tâches.
- Mettre à jour la statut d'une tâche (complétée ou non).
- Supprimer une tâche.
Étape 1 : Initialisation du projet
Commencez par créer un nouveau répertoire pour le projet et initialisez un environnement virtuel Python.
mkdir task_manager
cd task_manager
python3 -m venv venv
source venv/bin/activate # macOS/Linux
venv\Scripts\activate # Windows
Étape 2 : Installation des dépendances
Installez Flask et psycopg2.
pip install flask psycopg2-binary
Étape 3 : Création de l'application Flask
Créez un fichier app.py avec le contenu suivant :
from flask import Flask, request, render_template, redirect, url_for
import psycopg2
app = Flask(__name__)
def get_db_connection():
conn = psycopg2.connect(
host='localhost',
database='mydatabase',
user='myuser',
password='mypassword'
)
return conn
@app.route('/')
def index():
conn = get_db_connection()
cur = conn.cursor()
select_query = 'SELECT * FROM tasks ORDER BY id DESC'
cur.execute(select_query)
tasks = cur.fetchall()
cur.close()
conn.close()
return render_template('index.html', tasks=tasks)
@app.route('/add', methods=('GET', 'POST'))
def add():
if request.method == 'POST':
title = request.form['title']
description = request.form['description']
insert_task(title, description)
return redirect(url_for('index'))
return render_template('add.html')
@app.route('/update/<int:id>', methods=('GET', 'POST'))
def update(id):
if request.method == 'POST':
completed = True if request.form.get('completed') else False
update_task(id, completed)
return redirect(url_for('index'))
conn = get_db_connection()
cur = conn.cursor()
select_query = 'SELECT * FROM tasks WHERE id = %s'
cur.execute(select_query, (id,))
task = cur.fetchone()
cur.close()
conn.close()
return render_template('update.html', task=task)
@app.route('/delete/<int:id>')
def delete(id):
delete_task(id)
return redirect(url_for('index'))
def insert_task(title, description):
conn = get_db_connection()
cur = conn.cursor()
insert_query = 'INSERT INTO tasks (title, description) VALUES (%s, %s)'
cur.execute(insert_query, (title, description))
conn.commit()
cur.close()
conn.close()
def update_task(id, completed):
conn = get_db_connection()
cur = conn.cursor()
update_query = 'UPDATE tasks SET completed = %s WHERE id = %s'
cur.execute(update_query, (completed, id))
conn.commit()
cur.close()
conn.close()
def delete_task(id):
conn = get_db_connection()
cur = conn.cursor()
delete_query = 'DELETE FROM tasks WHERE id = %s'
cur.execute(delete_query, (id,))
conn.commit()
cur.close()
conn.close()
if __name__ == '__main__':
app.run(debug=True)
Étape 4 : Création des templates HTML
Créez un répertoire templates et ajoutez les fichiers suivants :
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Task Manager</title>
</head>
<body>
<h1>Task Manager</h1>
<form action="url_for('add')" method="post">
<input type="text" name="title" placeholder="Title" required>
<textarea name="description" placeholder="Description"></textarea>
<button type="submit">Add Task</button>
</form>
<ul>
{% for task in tasks %}
<li>
task[1] - task[2]
<form action="url_for('update', id=task[0])" method="post">
<input type="checkbox" name="completed" {% if task[3] %}checked{% endif %}>
<button type="submit">Update</button>
</form>
<form action="url_for('delete', id=task[0])" method="post">
<button type="submit">Delete</button>
</form>
</li>
{% endfor %}
</ul>
</body>
</html>
add.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Add Task</title>
</head>
<body>
<h1>Add Task</h1>
<form action="url_for('add')" method="post">
<input type="text" name="title" placeholder="Title" required>
<textarea name="description" placeholder="Description"></textarea>
<button type="submit">Add Task</button>
</form>
<a href="/">Back to Tasks</a>
</body>
</html>
update.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Update Task</title>
</head>
<body>
<h1>Update Task</h1>
<form action="url_for('update', id=task[0])" method="post">
<input type="text" name="title" value="task[1]" required>
<textarea name="description">task[2]</textarea>
<input type="checkbox" name="completed" {% if task[3] %}checked{% endif %}>
<button type="submit">Update</button>
</form>
<a href="/">Back to Tasks</a>
</body>
</html>
Étape 5 : Exécution de l'application
Assurez-vous que la base de données PostgreSQL est bien configurée et lancée. Ensuite, exécutez l'application Flask.
python app.py
Allez sur http://127.0.0.1:5000/ dans votre navigateur pour voir votre application en action.
Erreurs frequentes et debugging
1. Connexion échoue
Code incorrect :
conn = psycopg2.connect(
host='localhost',
database='mydatabase',
user='myuser',
password='mypassword'
)
Message d'erreur :
psycopg2.OperationalError: could not connect to server: No such file or directory
Is the server running locally and accepting connections on Unix domain socket "/var/run/postgresql/.s.PGSQL.5432"?
Code correct :
conn = psycopg2.connect(
host='localhost',
database='mydatabase',
user='myuser',
password='mypassword'
)
2. Table non trouvée
Code incorrect :
select_query = 'SELECT * FROM tasks'
cur.execute(select_query)
tasks = cur.fetchall()
Message d'erreur :
psycopg2.ProgrammingError: relation "tasks" does not exist
Code correct :
create_table_query = '''
CREATE TABLE IF NOT EXISTS tasks (
id SERIAL PRIMARY KEY,
title VARCHAR(100) NOT NULL,
description TEXT,
completed BOOLEAN DEFAULT False
);
'''
cur.execute(create_table_query)
3. Erreur d'insertion
Code incorrect :
insert_query = 'INSERT INTO tasks (title, description) VALUES (%s, %s)'
cur.execute(insert_query, ('Task 1', None))
Message d'erreur :
psycopg2.IntegrityError: null value in column "description" violates not-null constraint
DETAIL: Failing row contains (1, 'Task 1', null, f).
Code correct :
insert_query = 'INSERT INTO tasks (title, description) VALUES (%s, %s)'
cur.execute(insert_query, ('Task 1', ''))
Pour aller plus loin
1. Utiliser SQLAlchemy pour une gestion plus simple des données
Al SQLAlchemy est une bibliothèque ORM (Object-Relational Mapping) qui facilite la manipulation de la base de données en utilisant des objets Python.
Documentation : SQLAlchemy
2. Ajouter l'authentification et les rôles
Pour une application plus sécurisée, il est nécessaire d'ajouter une authentification et des rôles pour contrôler les accès.
Documentation Flask-Login : Flask-Login
3. Utiliser un système de migrations
Pour gérer les modifications de la structure de la base de données, il est recommandé d'utiliser un système de migrations comme Alembic.
Documentation Alembic : Alembic
Défi pratique
Créez une application Flask qui utilise PostgreSQL pour gérer un blog. Les fonctionnalités doivent inclure la création d'un article, la lecture des articles, la mise à jour d'un article et la suppression d'un article.
Documentation : Flask