← Retour à l'accueil
Spécialité · Ingénierie Django

Django, c'est là où on déposece qu'Odoo n'a pas à porter.

Trois plateformes en production où Django se tient à côté d'autre chose — Odoo, S3, des clients OAuth2, un front React. Multi-tenant via le RLS Postgres, des suites de tests parallèles qui finissent en quelques minutes, et une longue mémoire des parties de Django qui comptent quand la charge arrive.

Plateformes en prod
3
Plus grosse suite de tests
2 220 (Exiqtive)
Plus rapide, en parallèle
~2,5 min
Statut
Ouvert T3 2026
Vue d'ensemble

Django est le second pilier de l'atelier. Là où Odoo est la plateforme que nous choisissons quand la forme du métier est déjà en partie modélisée — clients, contrats, comptabilité — Django est celle que nous choisissons quand un système a besoin de sa propre forme, ou quand Odoo est juste pour une couche du stack et faux pour une autre.

Trois des plateformes que nous tenons aujourd'hui ont une couche Django. Exiqtive est Django de bout en bout — DRF + Celery + Channels, multi-tenant via le RLS Postgres, deux mille deux cents tests en deux minutes trente. L'app Django de MySpecialist vit à côté d'Odoo sur un Postgres partagé, rebâtie depuis une couche Symfony héritée en 2022. L'explorateur de documents Django d'Avataq lit la même base qu'Odoo écrit, et délivre à la demande des URL S3 présignées de soixante secondes.

Les décisions architecturales se cumulent. Une frontière multi-tenant qui vit au niveau du RLS Postgres ne peut pas fuir à travers un queryset oublié ; une classe OAuth2ScopesPermission sur chaque viewset impose une taxonomie de scopes que le front ne peut pas contourner ; une discipline `transaction.on_commit` sur les cascades Celery garantit que l'étape suivante ne tourne jamais contre un état à moitié commit. Deux ans et demi d'Exiqtive en production, toujours sur l'architecture dessinée au premier jour.

Ce que couvre cette pratique

Le périmètre, sans la liste de courses.

Multi-tenant par la ligne, pas par l'app01

L'isolation tenant est imposée au niveau Postgres par le RLS, pas seulement par la couche applicative. RLSMiddleware positionne la variable de session par requête ; les classes de permission s'empilent au-dessus ; la base refuse les lectures cross-tenant même quand un bug applicatif l'aurait laissé passer.

OAuth2 & DRF avec scopes02

django-oauth-toolkit pour l'émission ; OAuth2ScopesPermission sur chaque viewset ; scopes découpés read / write / admin par famille de ressources (employees:read, employees:write, assignments:recalc). Les connexions WebSocket s'authentifient de la même façon. Pas de cookie de session côté front.

Cascades async qui respectent la DB03

Celery + `transaction.on_commit` pour que l'étape suivante ne s'allume qu'après commit de l'écriture précédente. Retries avec backoff ; verrous Redis pour empêcher des recalculs concurrents du même enregistrement. Des cascades à cinq niveaux qui remontent de bas en haut dans un arbre organisationnel.

Versioning API qui laisse vieillir les contrats04

urls/v1.py, urls/v2.py, urls/shared.py en parallèle par app ; une classe CustomVersioning qui dispatche par query string ; les deux versions citoyennes de première classe dans la suite de tests jusqu'au retrait d'un contrat. Les clients payants ne sont pas migrés à notre rythme.

Channels & WebSocket05

Django Channels pour la livraison temps-réel, des connexions tenant authentifiées OAuth2, un routage de canaux supportant les chemins par entité. Les tests WebSocket tournent dans la même infrastructure parallèle que les tests HTTP.

Hybride avec Odoo sur un seul Postgres06

Une app Django lisant la base Odoo pour ses propres besoins — un explorateur de documents (Avataq), les outils marketplace qui s'installent mieux hors d'Odoo (MySpecialist). Frontières ORM nettes ; Django n'écrit jamais là où Odoo détient.

Une infra de tests qui se rentabilise07

--keepdb --parallel N, ALWAYS_EAGER pour Celery en tests, InMemoryChannelLayer pour Channels, LocMemCache pour le cache, un password hasher rapide. Suites de treize minutes ramenées à deux minutes trente sur une machine 8 cœurs. Seuil de couverture 80 % imposé en CI.

Migration & sauvetage08

Symfony → Django (MySpecialist, année une de la mission). Nouvelle couche Django sur un Postgres existant (Avataq). Architecture écrite pour qu'une équipe qui grandit puisse se brancher au système à mesure qu'il monte en charge.

Choix techniques signature

Quelques solves dont on se souvient encore.

01

Multi-tenant imposé par RLS (Exiqtive)

Politiques row-level security sur les tables tenantées ; RLSMiddleware positionne la variable de session avant chaque requête ; huit classes de permission empilées au-dessus. Un bug dans un filtre de queryset ne peut pas fuir entre comptes — la base refuse. Ceinture et bretelles avec les permissions applicatives.

02

Cascade de readiness à cinq niveaux (Exiqtive)

Le readiness remonte responsabilité → rôle → position assignment → employé → compte à travers des tâches Celery gated par `transaction.on_commit`. Retries avec max_retries=3, default_retry_delay=60. Des helpers publics (trigger_readiness_cascade_from_responsibility(id)) sont les points d'entrée ; les signals les appellent, jamais les tâches sous-jacentes directement.

03

Tests parallèles, 13 min → 2,5 min

--keepdb --parallel N avec N bases clones ; ALWAYS_EAGER pour Celery en tests ; InMemoryChannelLayer pour Channels ; LocMemCache pour le cache ; un password hasher plus rapide. Seuil de couverture 80 % imposé en CI. 2 220 tests en deux minutes trente sur une machine 8 cœurs.

04

Versioning API qui laisse vieillir les contrats (Exiqtive)

Chaque app porte urls/v1.py, urls/v2.py, urls/shared.py en parallèle, plus des arbres parallèles de serializers et viewsets. Une classe CustomVersioning lit ?version= et dispatche. Les deux versions sont citoyennes de première classe de la suite de tests jusqu'à ce qu'un contrat soit retiré.

05

Sauvetage Symfony → Django (MySpecialist)

L'année une de la mission a été surtout une reconstruction. La couche Symfony — formulaires faits main, pas de tests, couche d'outils internes mélangée à la logique métier — a été rebâtie en une app Django partageant le Postgres d'Odoo. De nouvelles fonctionnalités en jours, pas en semaines. Quatre ans plus tard, même base de code, même équipe.

06

Explorateur de documents Django sur le Postgres Odoo (Avataq)

Visualiseur en lecture seule verrouillé par documents.can_view_documents. Délivre à la demande une URL S3 présignée de soixante secondes. Django n'écrit jamais vers S3 ni vers les tables d'Odoo ; les documents ne s'asseyent jamais en mémoire. Deux stacks, un seul Postgres, une seule source de vérité.

Un projet qui mérite ce niveau de soin ?

Démarrer une conversation