Aus mehreren Gründen möchte ich in einigen meiner Django-Modelle eine UUID als Primärschlüssel verwenden. Wenn ich dies tue, kann ich dann weiterhin externe Apps wie "Contrib.comments", "Django-Voting" oder "Django-Tagging" verwenden, die generische Beziehungen über ContentType verwenden?
Am Beispiel von "Django-Voting" sieht das Abstimmungsmodell 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 "Integer-PK-angenommene" Problem eine häufige Situation für Apps 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?
^ Einige der Gründe: Ausblenden der Anzahl der Objekte, Verhindern des "Crawls" von URLs, Verwenden mehrerer Server zum Erstellen nicht widersprüchlicher Objekte, ...
default
.django_extensions.db.fields.UUIDField
wie von mitchf erwähnt verwenden, werden Sie keine Probleme mit Django-Süd-Migrationen haben - das von ihm erwähnte Feld hat eine integrierte Unterstützung für Süd-Migrationen.Wie in der Dokumentation zu sehen ist , gibt es ab Django 1.8 ein eingebautes UUID-Feld. Die Leistungsunterschiede bei Verwendung einer UUID gegenüber einer Ganzzahl sind vernachlässigbar.
Sie können diese Antwort auch überprüfen, um weitere Informationen zu erhalten.
quelle
Ich bin auf eine ähnliche Situation gestoßen und habe in der offiziellen Django-Dokumentation herausgefunden , dass der
object_id
nicht vom selben Typ sein muss wie der primäre Schlüssel des zugehörigen Modells. Zum Beispiel, wenn Sie Ihre allgemeine Beziehung für beide gültig sein sollen Integer und CharField ids einfach Ihr Setobject_id
ein sein CharField . Da ganze Zahlen zu Strings gezwungen werden können, ist dies in Ordnung. Gleiches gilt für UUIDField .Beispiel:
quelle
Das eigentliche Problem mit UUID als PK ist die Fragmentierung der Festplatte und die Verschlechterung der Einfügung, die mit nicht numerischen Kennungen verbunden sind. Da es sich bei der PK um einen Clustered-Index handelt, muss Ihre DB-Engine, wenn sie nicht automatisch inkrementiert wird, beim Einfügen einer Zeile mit einer ID niedrigerer Ordinalität auf Ihr physisches Laufwerk zurückgreifen, was bei UUIDs immer der Fall ist. Wenn Sie viele Daten in Ihrer Datenbank haben, kann es viele Sekunden oder sogar Minuten dauern, nur einen neuen Datensatz einzufügen. Und Ihre Festplatte wird schließlich fragmentiert und erfordert eine regelmäßige Defragmentierung der Festplatte. Das ist alles sehr schlecht.
Um diese Probleme zu lösen, habe ich kürzlich die folgende Architektur entwickelt, von der ich dachte, dass sie es wert wäre, geteilt zu werden.
Der UUID-Pseudo-Primärschlüssel
Mit dieser Methode können Sie die Vorteile einer UUID als Primärschlüssel (unter Verwendung einer eindeutigen Index-UUID) nutzen und gleichzeitig eine automatisch inkrementierte PK beibehalten, um die Fragmentierungsprobleme zu lösen und Leistungseinbußen bei einer nicht numerischen PK einzufügen.
Wie es funktioniert:
pkid
in Ihren DB-Modellen .id
Feld hinzu, damit Sie anstelle eines numerischen Primärschlüssels nach einer UUID-ID suchen können.to_field='id'
), damit Ihre Fremdschlüssel die Pseudo-PK anstelle der numerischen ID korrekt darstellen können.Im Wesentlichen werden Sie Folgendes tun:
Erstellen Sie zunächst ein abstraktes Django-Basismodell
Stellen Sie sicher, dass Sie das Basismodell anstelle von models.Model erweitern
Stellen Sie außerdem sicher, dass Ihre ForeignKeys auf das UUID-
id
Feld anstatt auf das automatisch inkrementiertepkid
Feld verweisen :Wenn Sie Django Rest Framework (DRF) verwenden, müssen Sie auch eine Base ViewSet-Klasse erstellen, um das Standardsuchfeld festzulegen:
Und erweitern Sie dies anstelle des Basis-ModelViewSet für Ihre API-Ansichten:
Weitere Hinweise zum Warum und Wie in diesem Artikel: https://www.stevenmoseley.com/blog/uuid-primary-keys-django-rest-framework-2-steps
quelle
Dies kann mithilfe eines benutzerdefinierten abstrakten Basismodells mithilfe der folgenden Schritte erfolgen.
Erstellen Sie zuerst einen Ordner in Ihrem Projekt, nennen Sie ihn Basemodell, und fügen Sie dann eine abstractmodelbase.py mit den folgenden Angaben hinzu:
Zweitens: Führen Sie dies in Ihrer gesamten Modelldatei für jede App aus
Der obige Modellvorfall ist also dem gesamten Feld des Baseabstract-Modells eigen.
quelle
Die Frage kann wie folgt umformuliert werden: "Gibt es eine Möglichkeit, Django dazu zu bringen, eine UUID für alle Datenbank-IDs in allen Tabellen anstelle einer automatisch inkrementierten Ganzzahl zu verwenden?".
Klar kann ich machen:
in allen meinen Tabellen, aber ich kann keinen Weg finden, dies zu tun für:
Dies scheint also eine fehlende Django-Funktion zu sein.
quelle