如何在Django中生成随机数作为对象的id /主键

goe*_*elv 1 random django primary-key

如何生成一个唯一的随机数来设置为django中对象的主键?

编辑 - 随机数不必是主键,但它必须对每个对象都是唯一的,以便我可以通过该数字引用/获取/调用对象.

Mat*_*ker 5

任何随机生成的数字唯一性受限于生成随机数的空间有多大.UUID/GUIDS长128位,因此碰撞的可能性很小.然而,除了版本4之外的所有UUID都不是完全随机的(即使有那些,一个半字节是固定的0x4),因此,UUID的一个子部分不能被认为是唯一的(有关更多信息,请参阅Raymond Chen关于GUID的帖子,另请注意虽然他在微软工作,并且他的大多数专栏都与微软有关,但这个专栏适用于使用UUID/GUID的任何内容.

所以,我们不要为此考虑UUID.首先需要决定的是你需要多大的空间,然后可以根据你的需要决定编码方案.这在很大程度上取决于您想要引用的项目数.由于生日问题,两个随机生成的数字之间碰撞的可能性非常低,维基上的生日攻击页面提供了近似值,即:

在此输入图像描述

H是可能值的数量,Q(H)是我们在遇到碰撞之前可以生成的项目数.我将假设冲突是不合需要的,因为要检查冲突,很可能你必须命中数据库以查看生成的数字是否存在,如果存在,则创建另一个并再次检查它.随着数据库中的项目越来越多,此过程将花费更长时间.当然,您仍然希望检查碰撞,但是您应该多次检查的可能性应该非常低.

所以,让我们从32位值开始.从上面的公式中,您将有大约82,000个项目生成,然后才能发生碰撞.如果你只期望几千或几万,这可能是一个可以接受的位数.对于其他一些值,这里是为多个位生成的项目数量:

16 bits: 320
24 bits: 5100
32 bits: 82,000
40 bits: 1.3*16^6
48 bits: 2.1*10^7
64 bits: 5.4*10^9
Run Code Online (Sandbox Code Playgroud)

我会认为这些计数是您期望在表中获得的最大值.如果它与安全相关,我会选择比你需要的范围大得多的范围(外部可见的用户ID,你不希望别人猜测其他人,最多几百个用户?48位是我最不习惯的那里)

在特定的说明中,我将使用random.getrandbits()为非安全相关项生成这些数字,对于那些,我会使用ssl.RAND_bytes()代替.

现在,对于问题的另一部分:将这些随机位编码为可打印的内容.最基本的是十六进制编码,我们是0-9A-F,并且长度将是您生成的位数除以4(32位标识符将是8个字符,40位10等).这将不区分大小写并且最容易键入.

另一种选择是base-64编码.这将导致输出(1/6)*n(向上舍入)字符(其中n是位数).因此对于32位,6个字符,40位,7个字符等.基本64值区分大小写,如果要将一个值放入URL中,则必须小心(+和/都是base 64编码的一部分,并且可以替换为.和_例如,用于URL编码).这将使它们更难键入,但对于较大的值则较短(对于64位值,base64为11个字符,而对于16位为16,则为此节省增加).

虽然这并没有直接回答你的问题(虽然我想你知道如何在数据库中为存储分配值,但请记住,这些值应该存储在数据库中的字符串编码形式中,或者作为BLOB,因为您的数据库可能会将这些值中的某些值视为已签名,并导致不良内容),它应该为您提供您需要知道的内容,以便为您的应用程序找出正确的组合.