如何生成唯一的8位数字,例如用于账户ID(Python,Django)

3
我需要为每个用户生成唯一的帐户ID(仅数字) UUID无法解决此问题,请帮助我!

1
数据库本身的id有什么问题? - Willem Van Onsem
2
你的最终目标是什么?是安全方面还是只是向用户展示数字?为什么不能使用UUID?你尝试过什么? - Sayse
我只需要数字ID,因为这个ID将用于支付,例如充值我的账户余额。 - Nursultan Ergeshov
用户有用户名或其他标识吗?如果是这样,也许可以采用基于哈希的方法来解决问题?例如,请参考此处:https://dev59.com/QmQo5IYBdhLWcg3wfPfK - der_herr_g
2
这听起来极易出错,仅使用一个数字...一个错误的数字,就会导致别人得到报酬。 - Sayse
显示剩余2条评论
4个回答

9

这里是您需要的内容。

import random
import string
''.join(random.choice(string.digits) for _ in range(8))

使用Python 3.6的random.choices()函数可以更加简洁地实现。

import random
import string
''.join(random.choices(string.digits, k=8))

避免可能的冲突:
尝试使用生成的ID创建新对象,如果遇到完整性错误,请重新创建ID。

例如 -

def create_obj():
    id = ''.join(random.choices(string.digits, k=8))
    try:
        MyModel.objects.create(id=id)
    except IntegrityError:
        create_obj()

或者

def create_unique_id():
    return ''.join(random.choices(string.digits, k=8))

def create_object():
    id = create_unique_id()
    unique = False
    while not unique:
        if not MyModel.objects.get(pk=id):
            unique = True
        else:
            id = create_unique_id()
    MyModel.objects.create(id=id)

感谢@WillemVanOnsem指出生成重复ID的机会,我提供的两个示例将创建一个新ID,直到获得唯一ID为止,但是随着数据库中行数的增加,获取唯一ID的时间将越来越长,并且当数据库中有如此多的记录(10^8)时,使用8位UID创建新记录将不可能,因为所有可能的组合已经存在,这时尝试创建新对象时将陷入无限循环。
如果Willem提供的统计数据是正确的,我认为发生冲突的可能性太高了。因此,我建议不要自己创建ID,而是使用django的默认自动字段或uuid,后者通过空间和时间保证唯一性。

这并不保证是唯一的:过一段时间后,可能会出现冲突。在1000个标记之后,发生冲突的概率为0.05%,在5000个标记之后,甚至达到了12%... - Willem Van Onsem
完成,添加了代码以避免与现有对象发生冲突,可能有更有效的方法来实现,也许其他人可以提供更好的代码。 - Vaibhav Vishal

2
假设你正在使用MYSQL,根据你的评论,你没有使用数据库PK,因为它们从1、2...开始。为什么不让PK从你的范围开始呢?例如:
ALTER TABLE user AUTO_INCREMENT = 10000000;

您可以将此代码放入您的自定义迁移中,参见manage.py makemigrations --empty

我认为其他数据库也有类似的方法


1
对于Django应用程序,我建议使用django.utils.crypto包中的get_random_string。它内部使用了Python secrets.choice。这样,如果机密接口发生更改,您就不必更改代码。
from django.utils.crypto import get_random_string

def generate_account_id():
    return get_random_string(8, allowed_chars='0123456789')

django.utils.crypto


0
如果您使用的是Python >= 3.6,可以使用 secrets.token_hex(nbytes) 这个函数来获取十六进制值字符串,然后将其转换为数字。为了进一步检测冲突,您还可以检查在Django模型中是否已经存在具有该ID的实例(如接受的回答所示)。
代码示例:
import secrets
hexstr = secrets.token_hex(4)
your_id = int(hexstr, 16)

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