Publié le
07 septembre 2022
tags : dev python django black outillage
Ami·e qui écrit du code avec le framework
Django , peut-être t'es-tu
mis à utiliser le fantastique formateur de code
black qui permet de se libérer les neurones
d'un peu de
bikesheding ?
Ton éditeur est bien configuré pour reformater ton code avec black automatiquement… Oui mais voilà… Quand tu génères tes migrations de base de donnée avec
./manage.py makemigrations
, tu dois repasser derrière pour formater le fichier .py de migration généré 😭 .
Voici une solution pour que makemigrations
produise une migration correctement formatée au sens de black .
Alors déjà, si tu utilises Django en version 4.1 ou supérieure, il n'y a rien
à faire, c'est inclus . Bonne
journée 😘…
Dans le cas contraire, la bricole suivante permet de faire passer black
automatiquement sur les migrations créées.
Surcharger la commande ./manage.py makemigrations
On va étendre le comportement de la commande makemigrations pour qu'elle inclue le reformatage.
Crée un fichier makemigrations.py à l'endroit suivant de ton projet Django (imaginons que le
projet se nomme « monprojet ») :
monprojet /
├── management
│ ├── commands
│ │ ├── __init__ . py
│ │ └── makemigrations . py
│ └── __init__ . py
[ … ]
(NB: il faut créer les dossiers management , commands et les fichiers (vides)
__init__.py si ils n'existent pas déjà).
Détail : on est en train de créer une commande
django-admin ,
et comme elle possède le même nom que la commande makemigrations inclue avec
Django, la notre va la « remplacer ».
… Avec le contenu suivant :
import glob
import subprocess
from django.core.management.commands.makemigrations import (
Command as CoreMakeMigrationsCommand ,
)
def black ( filepath : str ):
"""Calls black for a given path/wildcard
assume black is installed and in PATH, will fail on exception otherwise…
:param filepath: can be an unix glob including wildcard in file paths.
"""
paths_list = glob . glob ( filepath )
subprocess . check_call ([ "black" , "-q" , * paths_list ])
class Command ( CoreMakeMigrationsCommand ):
def write_migration_files ( self , changes ):
ret = super ( Command , self ) . write_migration_files ( changes )
for app_name , migrations in changes . items ():
for migration in migrations :
black ( f " { app_name } /migrations/ { migration . name } .py" )
return ret
def handle_merge ( self , * args , ** kwargs ):
super () . handle_merge ( * args , ** kwargs )
# There is nowhere to get reliably the name of generated file
# So call on all "migrations" folders.
black ( f "*/migrations" )
Détail : on se contente d'hériter le fonctionnement de la commande originale en lui
adjoignant une exécution de black par fichier de migration généré.
Il suffit ensuite d'utiliser ./manage.py makemigrations
comme d'habitude, joie 😎.
commentaires