Quand et comment utiliser ArrayField en Django?

Lorsque je devais lier un modèle à une liste de valeurs en SQL, j’avais pris l’habitude d’utiliser une relation de ce type:

Without ArrayField

Lorsque la liste est fixe (ou a minima non modifiée par l’utilisateur), il n’y a pas d’intérêt à disposer d’un modèle distinct. Ce type de relation a aussi l’inconvénient de nécessiter l’utilisation d’un prefetch_related() lors de l’affichage des modèles auxquels ils sont liés (Issue dans notre cas).


Heureusement, Django 1.8 expose un nouveau champ de base de données spécifique à PostgreSQL[1] nommé ArrayField qui permet d’utiliser les arrays. Le code précédent peut alors s’écrire :

With ArrayField

Je trouve l’API de filtrage particulièrement réussie toutefois l’intégration dans les formulaires et les templates est encore incomplète. Ainsi le champ de saisie sera affiché comme une liste de valeurs:

bug,feature

et names est une liste de chaînes qui ne sera ni validée par le code Python de l’ORM ni par la base de données, à vous de valider vos formulaires !

La première chose est donc de définir un widget de saisie et Brad Montgomery a eu la bonne idée de partager son code :

Ce widget peut alors être intégré dans l’administration de Django en définissant explicitement le widget à utiliser pour notre champ :

Chaque fois qu’un champ de modèle Django utilise une option choices, Django génère une méthode get_FOO_display() pour afficher l’étiquette associée à la valeur (par ex. « Release blocker » pour « blocker »). Malheureusement, il n’y pas d’équivalent pour les ArrayField, il faut alors écrire une méthode ou un filtre de template utilisant par exemple un dictionnaire du tuple des choices :

return u”,“.join([choice_dict[choice] for choice in choices])

La prise en charge de ArrayField est une bonne nouvelle pour les performances, toutefois en attendant une meilleure intégration dans Django prévoyez d’ajouter un peu de code d’intégration.

La prise en charge du type ARRAY progresse aussi dans SQLAlchemy (commit du jour !) et il existe déjà un moyen d’utiliser un ARRAY d’ENUM.

La prise en charge récente de fonctionnalités spécifiques aux différentes bases de données dans Django ouvre de nouvelles possibilités, stay tuned!

[1] disponible depuis au moins PostgreSQL 7 ;)