Section 11.2.5 : PostgreSQL — Configuration et pratique
🎯 Objectif pédagogique
Installer et configurer PostgreSQL localement ou via un service cloud, se connecter depuis Python, et exécuter des requêtes SQL depuis du code. Vous serez capable d'intégrer une base de données dans vos applications.
PostgreSQL en pratique
La théorie SQL est acquise. Place à la pratique : connecter une vraie base de données à du code Python. C'est le pont entre "savoir écrire du SQL" et "construire une application qui utilise une base de données".
Option 1 : PostgreSQL dans le cloud (recommandé pour les débutants)
Supabase offre une base PostgreSQL gratuite avec interface graphique :
- →Inscrivez-vous sur supabase.com
- →Créez un nouveau projet
- →Récupérez votre Database URL dans Settings → Database
- →Utilisez le SQL Editor intégré pour tester vos requêtes
Neon est une alternative : neon.tech — PostgreSQL serverless gratuit.
Option 2 : Installation locale
# Windows
winget install PostgreSQL.PostgreSQL
# macOS
brew install postgresql@16
brew services start postgresql@16
# Linux
sudo apt install postgresql postgresql-client
sudo systemctl start postgresql
# Vérification
psql --version
Se connecter depuis Python
pip install psycopg2-binary python-dotenv
import psycopg2
import os
from dotenv import load_dotenv
load_dotenv()
# Connexion
conn = psycopg2.connect(os.getenv("DATABASE_URL"))
cursor = conn.cursor()
# Créer la table
cursor.execute("""
CREATE TABLE IF NOT EXISTS applications (
id SERIAL PRIMARY KEY,
company VARCHAR(100) NOT NULL,
position VARCHAR(100) NOT NULL,
status VARCHAR(20) DEFAULT 'applied',
applied_date DATE DEFAULT CURRENT_DATE,
salary_min INTEGER
)
""")
conn.commit()
# Insérer (paramétré = sécurisé contre l'injection SQL)
cursor.execute(
"INSERT INTO applications (company, position, salary_min) VALUES (%s, %s, %s)",
("Mistral AI", "ML Engineer", 90000)
)
conn.commit()
# Lire
cursor.execute("SELECT * FROM applications ORDER BY applied_date DESC")
rows = cursor.fetchall()
for row in rows:
print(f"[\{row[0]\}] \{row[1]\} — \{row[2]\} (\{row[3]\})")
# Fermer
cursor.close()
conn.close()
Injection SQL — La faille de sécurité n°1
N'insérez JAMAIS de variables directement dans le SQL :
# ❌ DANGEREUX (injection SQL possible)
cursor.execute(f"SELECT * FROM users WHERE name = '\{user_input\}'")
# ✅ SÉCURISÉ (requête paramétrée)
cursor.execute("SELECT * FROM users WHERE name = %s", (user_input,))
Si user_input = "'; DROP TABLE users; --", la version dangereuse supprime votre table.
Pattern propre : gestionnaire de contexte
import psycopg2
from contextlib import contextmanager
@contextmanager
def get_db():
conn = psycopg2.connect(os.getenv("DATABASE_URL"))
try:
yield conn
conn.commit()
except Exception:
conn.rollback()
raise
finally:
conn.close()
# Utilisation propre
with get_db() as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM applications WHERE status = %s", ("interview",))
interviews = cursor.fetchall()
print(f"Entretiens en cours : \{len(interviews)\}")
🏋️ Exercice pratique (25 minutes)
- →Créez un compte Supabase ou Neon
- →Créez les tables
usersetapplications - →Écrivez un script Python qui :
- →Insère 5 candidatures
- →Affiche toutes les candidatures triées par date
- →Met à jour le statut d'une candidature
- →Compte les candidatures par statut
Pourquoi utiliser des requêtes paramétrées (%s) au lieu de f-strings en SQL ?
Que fait conn.rollback() dans la gestion d'erreur ?