PROJET AUTOBLOG


Sam et Max

source: Sam et Max

⇐ retour index

Utiliser des UUID comme primary key avec l’ORM de Django

jeudi 6 décembre 2012 à 15:59

Par défaut Django ajoute automatiquement un champ id à tous les modèles, et le configure pour être un entier qui s’auto incrémente puis le désigne comme la clé primaire. Il est néanmoins possible d’utiliser un autre champ comme clé primaire pour sa table: un slug ou un identifiant métier. Dans notre cas, on va voir comment utiliser un UUID.

Un UUID est un identifiant généré de manière pseudo aléatoire qui a une forte probabilité d’être unique dans le monde entier, il y a 4×10³⁷ combinaisons possibles pour les versions des algos récents. Selon le paradoxe des anniversaires, il faudrait créer un milliard de UUID par seconde pendant 100 ans pour que le prochain ait 50% de chance d’être un doublon. Normalement pour votre site de fans club des limules hermaphrodites, ça devrait être suffisant.

Utiliser des UUID possède de nombreux avantages car ils sont plus ou moins garantis d’être uniques, et ainsi:

Pour toutes ces raisons, les bases de données NoSQL (CouchDB, MongoDB, etc) utilisent depuis longtemps les UUID comme clés primaires par défaut. Le moteur de base de données de Google, Big Table, utilise des UUID.

Pourtant les UUID ne sont pas exempts de défauts:

Les UUID ne sont donc pas la solution miracle à tous les soucis, mais ils sont tout de même mon choix par défaut en ce moment ne serait-ce que pour les fixtures. Je gagne les performances sur le caching et le parallélisme, et un peu de lenteur sur les JOINS est quelque chose que je peux supporter. Pour les gros sites, les JOINS sont de tout façon votre ennemi juré et on finit toujours par tweaker à grand coup de dé-normalisation.

On peut faire passer ses modèles Django aux UUID en faisant:

from uuid import uuid4
 
class MotDElle(object):
    ...
    id = models.CharField(max_length=36, primary_key=True,
                          default=lambda: str(uuid.uuid4()), editable=False)

Ou, si vous utilisez django_extensions (et vous devriez, ne serait-ce que pour shell_plus et runserver_plus):

from django_extensions.db.fields import UUIDField
 
class MotDElle(object):
    ...
    id = UUIDField(primary_key=True)

Ce qui a l’avantage de caster la valeur en un objet UUID, et non une bête string, à la lecture.

Malheureusement, pour le moment il n’y a aucune implémentation officielle de Django pour utiliser les UUID. Cela a des conséquences fort ennuyeuses:

Un ticket pendouille depuis 5 ans sur la question. Je vous invite d’ailleurs à le spammer jusqu’à ce que réouverture s’en suive. Et le premier qui me dit “t’as qu’à l’implémenter, toi”, je lui retourne un tampon dans la poire.