Django的UUIDField如何在PostgreSQL中生成UUID?

13
阅读了这篇博客文章后(链接),我想更多地了解Django如何生成uuid,因为我正在将它们用作我的主键。根据文档(链接),Django依赖于Python的UUID模块(链接)。但是,有很多种UUID,我不清楚在Django中生成哪种类型的UUID,如果可选择的话该如何选择。
最后,考虑到博客中指出的分裂问题,假设 uuid_generate_v1mc 在Python或Django中不可用,是否有一种方法强制使用它?
2个回答

28
使用Django和/或Python在Postgresql中生成UUID是如何实现的?
但是,UUID有很多种,我不清楚Django生成的是哪一种。
在Django中,当您将UUIDField用作主键时,它不会为您生成UUID,您需要在保存对象之前自己生成。可能自从我上次使用UUIDField以来有所改变,但是在我最后使用UUIDField时,您必须自己指定UUID值(例如,当您创建对象时,Django不允许您保存具有空UUID的对象并生成一个)。查看Django文档示例加强了我的想法,因为它们提供了一个default=uuid.uuid4(),例如在主键中。
class MyUUIDModel(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
                                                    ^
                                                    |__ calls uuid.uuid4() 

选择哪个UUID版本

要比较不同UUID版本的属性,请参见此问题:Which UUID version to use?

对于许多应用程序而言,UUID4就足够了

如果您只想生成UUID并继续进行生活,像上面示例中的uuid.uuid4()一样就行了。UUID4是随机UUID,发生冲突的可能性非常小,尤其是如果您每秒钟不会生成大量UUID。

最后,假设在Python或Django中直接使用uuid_generate_v1mc不可用,鉴于博客文章指出的碎片化问题,是否有方法强制使用它?

一个带有随机MAC地址的Python UUID1,例如uuid-osspuuid_generate_v1mc

您链接的博客提到了使用UUID1。 Python的uuid.uuid1()接受一个参数,该参数用于替代默认的真实硬件MAC地址(48位)。因为这些随机位是UUID1的结尾,所以UUID1的前几位可以是顺序/基于时间戳的,以限制索引的碎片化。

因此,

uuid.uuid1(random_48_bits)

应该可以得到与uuid_generate_v1mc相似的结果,它是带有随机MAC地址的UUID1。

为了生成一个随机的48位数,我们可以使用以下虚拟示例:

import random
random_48_bits = random.randint(0, 2**48 - 1)

试一试:

>>> import uuid
>>> import random
>>> 2 ** 48 - 1
281474976710655
>>> uuid.uuid1(random.randint(0, 281474976710655))
UUID('c5ecbde1-cbf4-11e5-a759-6096cb89d9a5')

现在将其制作成函数,并将其用作Django UUIDFielddefault

自定义UUID以及Instagram的示例

请注意,完全可以想出自己的自定义UUID方案,并使用可用位来编码对应用程序有用的信息。

例如,您可以使用一些位来编码给定用户的国家/地区,一些位来存储时间戳,一些随机位等。

您可能需要阅读Instagram(建立在Django和PostgreSQL上)如何构建自己的UUID方案以帮助分片的文章。


1
回复:Twitter Snowflake:“我们已经停用了最初版本的Snowflake,并正在开发基于Twitter-server的下一个版本,以一种形式运行在任何地方,而不需要Twitter自己的基础设施服务。” https://github.com/twitter/snowflake - Malik A. Rumi
碎片化问题怎么办? - Malik A. Rumi
@MalikA.Rumi 添加了一个代码片段,展示如何生成一个带有随机48位MAC地址的UUID1,就像博客中建议的uuid_generate_v1mc一样,以限制索引碎片化。 - bakkal
谢谢,非常详细的回答。我期待着 Twitter Snowflake 带来的一切,并将尝试您的方法来创建自定义 UUID。另外,请注意,今天我看到了这个关于性能的 SO 回答:https://dev59.com/nV0a5IYBdhLWcg3w07zt。 - Malik A. Rumi
1
如果我每秒钟生成大量的uuid怎么办?例如,我将UUIDField添加到包含93,000条记录的模型中。当我运行迁移时,我一直收到IntegrityError - uuid发生冲突。有没有办法保证生成的uuid是唯一的? - nnyby

0
from django.db.models import Func, UUIDField

class RandomUUID(Func):
    template = "uuid_in(md5(random()::text || clock_timestamp()::text)::cstring)"
    output_field = UUIDField()



def add_guid(apps, schema_editor):
    MyModel= apps.get_model("app", "MyModel")
    MyModel.objects.update(guid=lib_models.RandomUUID())


class Migration(migrations.Migration):
    ...
    operations = [
        migrations.RunPython(add_guid, reverse_code=migrations.RunPython.noop),
    ]

1
目前你的回答不够清晰,请编辑并添加更多细节,以帮助其他人理解它如何回答问题。你可以在帮助中心找到有关如何编写好答案的更多信息。 - Community

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接