wake-up-neo.net

Verwenden einer UUID als Primärschlüssel in Django Modellen (Auswirkungen auf generische Beziehungen)

Aus einer Reihe von Gründen ^ möchte ich in einigen meiner Django Modelle eine UUID als Primärschlüssel verwenden. Wenn ich dies tue, kann ich auch weiterhin externe Apps wie verwenden "contrib.comments", "Django-voting" oder "Django-tagging", die generische Beziehungen über ContentType verwenden?

Am Beispiel von "Django-Voting" sieht das Voting-Modell folgendermaßen aus:

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)

Diese App scheint davon auszugehen, dass der Primärschlüssel für das Modell, über das abgestimmt wird, eine Ganzzahl ist.

Die integrierte Kommentar-App scheint jedoch in der Lage zu sein, nicht ganzzahlige PKs zu verarbeiten:

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

Ist dieses Problem mit der Annahme einer Ganzzahl-PK eine häufige Situation für Anwendungen von Drittanbietern, die die Verwendung von UUIDs zu einem Problem machen würden? Oder verstehe ich diese Situation möglicherweise falsch?

Gibt es eine Möglichkeit, UUIDs als Primärschlüssel in Django zu verwenden, ohne zu viele Probleme zu verursachen?


74
mitchf

Ein UUID-Primärschlüssel verursacht nicht nur Probleme mit allgemeinen Beziehungen, sondern auch mit der Effizienz im Allgemeinen: Jeder Fremdschlüssel ist erheblich teurer - sowohl beim Speichern als auch beim Beitreten - als ein Computer-Word.

Für nichts ist es jedoch erforderlich, dass die UUID der Primärschlüssel ist: Machen Sie sie einfach zu einem sekundären Schlüssel, indem Sie Ihr Modell durch ein UUID-Feld mit unique=True Ergänzen. Verwenden Sie den impliziten Primärschlüssel wie gewohnt (systemintern) und verwenden Sie die UUID als externe Kennung.

42
Pi Delport

Wie in der Dokumentation zu sehen , ab Django 1.8 gibt es ein eingebautes UUID-Feld. Die Leistungsunterschiede bei der Verwendung einer UUID gegenüber einer Ganzzahl sind vernachlässigbar.

import uuid
from Django.db import models

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

Sie können auch überprüfen Sie diese Antwort für weitere Informationen.

182
keithhackbarth

Ich bin auf eine ähnliche Situation gestoßen und habe in der official Django documentation festgestellt, dass die object_id muss nicht vom selben Typ sein wie primary_key des zugehörigen Modells. Wenn Sie beispielsweise möchten, dass Ihre generische Beziehung sowohl für IntegerField als auch CharField IDs gültig ist, legen Sie einfach Ihr object_id ein CharField sein. Da ganze Zahlen in Zeichenfolgen umgewandelt werden können, ist dies in Ordnung. Gleiches gilt für UUIDField.

Beispiel:

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