Использование UUID в качестве первичного ключа в моделях Django (влияние общих отношений)


по ряду причин^, я хотел бы использовать UUID в качестве первичного ключа в некоторых из моих моделей Django. Если я это сделаю, я все равно смогу использовать внешние приложения, такие как "contrib.комментарии", "Джанго-голосование" или "Джанго-тегов", которые используют родовых отношений через значение contentType?

используя "django-голосование" в качестве примера, модель голосования выглядит так:

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)

Это приложение, по-видимому, предполагает, что первичный ключ для голосуемой модели является целым числом.

в встроенное приложение для комментариев, похоже, способно обрабатывать нецелые PKs, хотя:

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" общей ситуацией для сторонних приложений, которые сделают использование UUIDs болью? Или, возможно, я неправильно понимаю эту ситуацию?

есть ли способ использовать UUIDs в качестве первичных ключей в Django, не вызывая слишком много проблем?


^ Некоторые из причин: скрытие подсчетов объектов, предотвращение обхода url-адреса "id", использование нескольких серверы для создания неконфликтных объектов, ...
3 59

3 ответа:

первичный ключ UUID вызовет проблемы не только с родовыми отношениями, но и с эффективностью в целом: каждый внешний ключ будет значительно дороже-как хранить, так и присоединять-чем машинное слово.

однако ничто не требует, чтобы UUID был первичным ключом: просто сделайте его среднее ключ, дополняя вашу модель с полем uuid с unique=True. Используйте неявный первичный ключ как обычный (внутренний для вашей системы) и используйте UUID в качестве своего внешний идентификатор.

Django 1.8 теперь имеет встроенное поле UUID. Различия в производительности при использовании UUID vs integer незначительны.

import uuid
from django.db import models

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

я столкнулся с подобной ситуацией и узнал в официальная документация Django, что object_id Не обязательно должен быть того же типа, что и primary_key соответствующие модели. Например, если вы хотите, чтобы ваши общие отношения были действительны для обоих IntegerField и страничке id, просто установите свой object_id быть страничке. Поскольку целые числа могут принудительно переходить в строки, все будет в порядке. То же самое касается 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)