Makina Blog
L'aventure de la contribution : validation automatique des contraintes dans Django 4.1
J'ai eu l'occasion de contribuer une nouvelle fonctionnalité dans Django au cours de l'année dernière : la validation automatique des contraintes. Découvrez dans cet article, le processus de contribution suivi ainsi que le fonctionnement de cette nouveauté.
Comme beaucoup de contributions, le besoin m'est apparu pendant le développement d'un projet sur lequel je travaillais. J'ai eu besoin d'avoir une contrainte d'unicité un peu plus complexe que celle utilisée habituellement, et j'ai donc rajouté une condition dessus pour n'avoir la contrainte que sur certaines instances de mon modèle.
Petit exemple pour illustrer, imaginons que nous sommes en 4.0 avec le modèle suivant :
class User(models.Model):
username = models.CharField(max_length=50, unique=True)
active = models.BooleanField(default=True)
Lorsque nous essayons de créer un User avec un username déjà existant, le modèle valide que ce username n'est pas déjà présent en base de données. Cette information remonte dans les Form (et ModelForm) et est donc gérée automatiquement :

Maintenant, imaginons que nous ne voulons contraindre les utilisateurs actifs à avoir un username unique. Il suffit d'utiliser UniqueConstraint avec une condition, plutôt simple jusque là. Sauf que :
class User(models.Model):
username = models.CharField(max_length=50)
active = models.BooleanField(default=True)
class Meta:
constraints = [
UniqueConstraint('username', condition=Q(active=True), name='user_unique_active')
]

Boom Bada Boom. Django ne gérait absolument pas cette contrainte, à cause de la condition. La solution tout en gardant la même version fut de valider l'unicité en complétant la validation du modèle directement. Le problème était le suivant, j'avais beaucoup de modèles différents avec le même genre de contraintes. Ainsi, tous les modèles auraient du être modifiés et il aurait fallu penser à mettre à jour la validation si la contrainte un jour était changée. Pensez à vos tests unitaires de non régression dans ces cas là !
Je ne suis sûrement pas le premier à avoir eu ce besoin, et je ne serais certainement pas le dernier ! J'ai donc vérifié si une meilleure manière de faire existait.
Contribuer
Première chose à faire : tester sur la dernière version stable, puis sur la dernière version de développement (branche main du dépôt). Le problème étant toujours présent, les prochains arrêts sont le bug tracker et la mailing list. Je ne trouve pas ce qui m'intéresse, mais rapporter un problème c'est déjà contribuer. Début juin 2021, je décide donc de poster un message sur cette même mailing list pour me renseigner.
La réponse : un ticket existe bien créé en juin 2019, et faisant même mention d'un commentaire évoquant le sujet datant de 2012 ! S'ensuit de nombreux d'allers-retours donnant naissance à une première implémentation dans cette magnifique pull-request en juillet 2021.
Et c'est le début de la période la plus longue : relectures, refactoring, relances, validations par plusieurs développeurs, etc. Certaines fonctionnalités nécessaires mais indépendantes ont été extraites et commitées à part. La pull request est découpée en trois parties distinctes, permettant de l'intégrer progressivement. C'est finalement en mai 2022, presque un an après avoir commencé cette contribution, que la pull request est acceptée entièrement, juste à temps pour Django 4.1.
Profiter 🙂
Et si voir cette fonctionnalité dans les notes de mise à jour n'est pas une récompense suffisante, il suffit de mettre à jour son projet et d'en profiter !
UniqueConstraint(
'username',
condition=Q(active=True),
name='user_unique_active',
violation_error_message="Un utilisateur actif avec ce nom existe déjà."
)


Formations associées
Formations Django
Toutes les sessions sont actuellement complètes.
Pour plus d'informations, n'hésitez pas à nous contacter.
Voir la formationFormations Django
Aucune session de formation n'est prévue pour le moment.
Pour plus d'informations, n'hésitez pas à nous contacter.
Voir la formationActualités en lien

Makina Corpus sponsor argent de la PyConFr 2023
L'événement français incontournable de la communauté Python, la PyConFR se déroule à Bordeaux du 16 au 19 février 2023. Makina Corpus est heureuse de soutenir cette année encore la PyConFR. Nos experts seront présents et vous proposent des conférences !

Comment développer et intégrer un composant VueJS indépendant dans Django ?
Si vous avez un besoin précis et complexe de JavaScript dans une page ou pour un widget, il peut être intéressant de développer en VueJS sans pour autant recourir à une SPA.

DjangoCon Porto 2022 : mise en œuvre du Domain-driven design (DDD) dans Django
Dans le cadre de la conférence DjangoCon Europe à Porto du 21 au 25 septembre 2022, nous présenterons notre retour d'expérience sur l'intégration de quelques concepts DDD dans OSIS, un projet open-source chez notre partenaire l'UCLouvain.