Utiliser un UUID comme clé primaire dans les modèles Django (impact des relations génériques)

Pour un certain nombre de raisons, je voudrais utiliser un UUID comme clé primaire dans certains de mes modèles Django. Si je le fais, pourrai-je quand même utiliser des applications externes comme “consortingb.comments”, “django-Vote” ou “django-tagging” qui utilisent des relations génériques via ContentType?

En utilisant le “vote-django” comme exemple, le modèle de vote ressemble à ceci:

class Vote(models.Model): user = models.ForeignKey(User) content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() object = generic.GenericForeignKey('content_type', 'object_id') vote = models.SmallIntegerField(choices=SCORES) 

Cette application semble supposer que la clé primaire du modèle soumis au vote est un entier.

L’application de commentaires intégrée semble être capable de gérer les PK non entières, bien que:

 class BaseCommentAbstractModel(models.Model): content_type = models.ForeignKey(ContentType, verbose_name=_('content type'), related_name="content_type_set_for_%(class)s") object_pk = models.TextField(_('object ID')) content_object = generic.GenericForeignKey(ct_field="content_type", fk_field="object_pk") 

Est-ce que ce problème de type «Entier-PK-assume» est une situation courante pour les applications tierces qui rendrait difficile l’utilisation d’UUID? Ou peut-être ai-je mal interprété cette situation?

Est-il possible d’utiliser les UUID comme clés primaires dans Django sans causer trop de problèmes?


^ Quelques-unes des raisons: masquer le nombre d’objects, empêcher l’id “d’exploration”, utiliser plusieurs serveurs pour créer des objects non conflictuels, …

Une clé primaire UUID posera des problèmes non seulement avec les relations génériques, mais avec une efficacité en général: chaque clé étrangère sera beaucoup plus coûteuse – à la fois pour stocker et pour joindre – qu’un mot machine.

Cependant, rien ne nécessite que l’UUID soit la clé primaire: il suffit d’en faire une clé secondaire , en complétant votre modèle par un champ uuid avec unique=True . Utilisez la clé primaire implicite normalement (interne à votre système) et utilisez l’UUID comme identifiant externe.

Django 1.8 a maintenant un champ UUID intégré. Les différences de performances lors de l’utilisation d’un UUID vs entier sont négligeables.

 import uuid from django.db import models class MyUUIDModel(models.Model): id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False) 

Je suis tombé sur une situation similaire et j’ai découvert dans la documentation officielle de Django que object_id ne devait pas être du même type que la méthode primary_key du modèle associé. Par exemple, si vous souhaitez que votre relation générique soit valide à la fois pour les identifiants IntegerField et CharField , définissez simplement object_id comme CharField . Comme les entiers peuvent forcer les chaînes, ça ira. Même chose pour UUIDField .

Exemple:

 class Vote(models.Model): user = models.ForeignKey(User) content_type = models.ForeignKey(ContentType) object_id = models.CharField(max_length=50) # <<-- This line was modified object = generic.GenericForeignKey('content_type', 'object_id') vote = models.SmallIntegerField(choices=SCORES)