首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Django模型中使用UUID作为主键(泛型关系影响)

在Django模型中使用UUID作为主键(泛型关系影响)
EN

Stack Overflow用户
提问于 2010-10-15 02:10:35
回答 6查看 62.9K关注 0票数 104

由于一些原因^,我想在我的一些Django模型中使用UUID作为主键。如果我这样做了,我还能使用诸如"contrib.comments“、"django-voting”或"django-tagging“这样的外部应用吗?这些应用通过ContentType使用泛型关系?

以"django-voting“为例,投票模型如下所示:

代码语言:javascript
复制
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:

代码语言:javascript
复制
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")

这种“整数PK假设”的问题是不是第三方应用程序的常见情况,这会使使用UUID成为一种痛苦?或者,可能,我误解了这种情况?

有没有一种方法可以在Django中使用UUID作为主键而不会造成太多麻烦?

^一些原因:隐藏对象计数,防止url "id爬行“,使用多个服务器创建不冲突的对象,...

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2010-10-16 00:35:24

UUID主键不仅会导致泛型关系的问题,而且还会导致效率方面的问题:每个外键的存储和连接成本都要比机器字高得多。

但是,不需要UUID作为主键:只需通过使用unique=True补充模型的uuid字段,使其成为辅键即可。像平常一样使用隐式主键(在系统内部),并使用UUID作为外部标识符。

票数 65
EN

Stack Overflow用户

发布于 2015-02-12 12:54:46

As seen in the documentation,从Django1.8开始有一个内置的UUID字段。使用UUID与使用整数时的性能差异可以忽略不计。

代码语言:javascript
复制
import uuid
from django.db import models

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

你也可以通过check this answer获取更多信息。

票数 252
EN

Stack Overflow用户

发布于 2019-11-07 04:21:45

将UUID用作PK的真正问题是与非数字标识符相关的磁盘碎片和插入性能下降。因为PK是一个聚集索引(除了PostgreSQL之外的几乎所有RDBMS中),当它不是自动递增的时候,在插入具有较低序号的行时,您的DB引擎将不得不重新使用您的物理驱动器,这将一直发生在UUID中。当您在数据库中获得大量数据时,仅插入一条新记录就可能需要几秒钟甚至几分钟。并且您的磁盘最终会变得碎片,需要定期进行磁盘碎片整理。这一切真的很糟糕。

为了解决这些问题,我最近提出了以下我认为值得分享的架构。

UUID伪主键

此方法允许您利用UUID作为主键的优势(使用唯一索引UUID),同时维护自动递增的PK,以解决拥有非数字PK带来的碎片和插入性能下降问题。

工作原理:

  1. 在数据库模型上创建名为pkid的自动递增主键。
  2. 添加一个唯一索引的UUID id字段,以允许您按UUID id而不是数字主键进行搜索。
  3. 将ForeignKey指向UUID (使用to_field='id'),以允许外键正确表示伪PK而不是数字ID。<代码>H213<代码>G214

基本上,您将执行以下操作:

首先,创建一个抽象的Django基础模型

代码语言:javascript
复制
class UUIDModel(models.Model):
    pkid = models.BigAutoField(primary_key=True, editable=False)
    id = models.UUIDField(default=uuid.uuid4, editable=False, unique=True)

    class Meta:
        abstract = True

确保扩展基本模型,而不是models.Model

代码语言:javascript
复制
class Site(UUIDModel):
    name = models.CharField(max_length=255)

还要确保您的ForeignKeys指向UUID id字段,而不是自动递增的pkid字段:

代码语言:javascript
复制
class Page(UUIDModel):
    site = models.ForeignKey(Site, to_field='id', on_delete=models.CASCADE)

如果您正在使用Django Rest Framework (DRF),请确保还创建了一个基本ViewSet类来设置默认搜索字段:

代码语言:javascript
复制
class UUIDModelViewSet(viewsets.ModelViewSet):
    lookup_field = 'id' 

并扩展它而不是你的API视图的基础ModelViewSet:

代码语言:javascript
复制
class SiteViewSet(UUIDModelViewSet):
    model = Site

class PageViewSet(UUIDModelViewSet):
    model = Page

有关本文中的原因和方法的更多说明:https://www.stevenmoseley.com/blog/uuid-primary-keys-django-rest-framework-2-steps

票数 14
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3936182

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档