web-dev-qa-db-ja.com

Djangoモデル(一般的な関係への影響)でUUIDを主キーとして使用する

いくつかの理由により^、DjangoモデルのいくつかでUUIDを主キーとして使用したいと思います。その場合、ContentTypeを介した一般的な関係を使用する「contrib.comments」、「Django-voting」、「Django-tagging」などの外部アプリを引き続き使用できますか?

「Django-voting」を例として使用すると、投票モデルは次のようになります。

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)

このアプリは、投票されるモデルの主キーが整数であると想定しているようです。

ただし、組み込みのコメントアプリは、整数ではないPKを処理できるようです。

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

この「integer-PK-assumed」問題は、UUIDを使用するのが面倒になるサードパーティアプリの一般的な状況ですかまたは、おそらく、私はこの状況を誤解していますか?

Djangoで主キーとしてUUIDを使用する方法はありますか?


74
mitchf

UUIDの主キーは、一般的な関係だけでなく、一般的な効率でも問題を引き起こします。すべての外部キーは、マシンのWordよりもはるかに高価です(格納および参加の両方)。

ただし、UUIDを主キーにする必要はありません。モデルをunique=Trueでuuidフィールドで補完することで、secondaryキーにするだけです。暗黙の主キーを通常どおり(システムの内部)使用し、UUIDを外部識別子として使用します。

42
Pi Delport

ドキュメントに記載されているように 、from Django 1.8にはUUIDフィールドが組み込まれています。UUIDと整数を使用した場合のパフォーマンスの違いはごくわずかです。

import uuid
from Django.db import models

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

この回答を確認 で詳細を確認することもできます。

182
keithhackbarth

私は同様の状況に遭遇し、 official Django documentation で、object_idは、関連するモデルのprimary_keyと同じ型である必要はありません。たとえば、ジェネリック関係をIntegerFieldCharFieldidの両方に対して有効にしたい場合は、object_idは、CharFieldになります。整数は強制的に文字列に変換できるため、問題ありません。 UUIDFieldについても同様です。

例:

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