web-dev-qa-db-fra.com

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

Pour un certain nombre de raisons ^, j'aimerais utiliser un UUID comme clé primaire dans certains de mes modèles Django. Si je le fais, serai-je toujours en mesure d'utiliser des applications extérieures comme "contrib.comments", "Django-vote" ou "Django-tagging" qui utilisent des relations génériques via ContentType?

En utilisant "Django-vote" comme exemple, le modèle 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 des PK non entiers, cependant:

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

Ce problème "supposé par PK entier" est-il une situation courante pour les applications tierces qui rendraient difficile l'utilisation des UUID? Ou, peut-être, suis-je mal interprété cette situation?

Existe-t-il un moyen d'utiliser les UUID comme clés primaires dans Django sans causer trop de problèmes?


74
mitchf

Une clé primaire UUID causera des problèmes non seulement avec les relations génériques, mais avec l'efficacité en général: chaque clé étrangère sera beaucoup plus coûteuse - à la fois pour stocker et pour se connecter - qu'une machine Word.

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

42
Pi Delport

Comme vu dans la documentation , à partir de Django 1.8 il y a 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)

Vous pouvez également cochez cette réponse pour plus d'informations.

182
keithhackbarth

J'ai rencontré une situation similaire et j'ai découvert dans le officiel Django , que le object_id ne doit pas être du même type que la clé_principale du modèle associé. Par exemple, si vous souhaitez que votre relation générique soit valide pour IntegerField et CharField id's, il suffit de définir votre object_id pour être un CharField . Étant donné que les entiers peuvent être contraints en chaînes, tout ira bien. Il en va de même 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)
10
Jordi