Makina Blog

Le blog Makina-corpus

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 :

Validation de la contrainte unique

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')
        ]
Erreur lors de l'insertion avec la contrainte unique avec condition

 

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à."
)

 

Contrainte unique avec condition

 

Tweet aventure de la contribution 2

 

Formations associées

Formations Python

Toulouse Du 20 au 22 mars 2023

Voir la formation

Formations Django

Toutes les sessions sont actuellement complètes.

Pour plus d'informations, n'hésitez pas à nous contacter.

Voir la formation

Formations Django

Aucune session de formation n'est prévue pour le moment.

Pour plus d'informations, n'hésitez pas à nous contacter.

Voir la formation

Actualités en lien

Image
PyConFR
01/02/2023

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 !

 

Voir l'article
Image
Django VuJs
06/10/2022

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.

Voir l'article
Image
DjangoCon Europe 2022
21/09/2022

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.

Voir l'article

Inscription à la newsletter

Nous vous avons convaincus