I need to generate unique account ID for each user.(only numeric) UUID can't solve this problem, pls help me!
-
1What is wrong with the `id` of the database itself? – Willem Van Onsem Sep 21 '18 at 08:30
-
it starts with 1,2, etc, i need only 8 length numbers – Nursultan Ergeshov Sep 21 '18 at 08:41
-
well you can add leading zeros, or add 1000000 to the `id`. – Willem Van Onsem Sep 21 '18 at 08:42
-
2What is your end goal here? is it the security aspect or just to show the number to a user? Why can't you use a UUID? What have you tried? – Sayse Sep 21 '18 at 08:44
-
i need only digit id, cause this id will be used for payments, for example replenish my account balance – Nursultan Ergeshov Sep 21 '18 at 08:47
-
Do the users have usernames or something? In this case, maybe a hashing-bashed approach could work? See e.g. here: https://stackoverflow.com/questions/16008670/python-how-to-hash-a-string-into-8-digits – der_herr_g Sep 21 '18 at 08:48
-
2That sounds extremely error prone to use just a number... one wrong digit and someone else is getting paid – Sayse Sep 21 '18 at 08:48
4 Answers
Here you go
import random
import string
''.join(random.choice(string.digits) for _ in range(8))
Even shorter with python 3.6 using random.choices()
import random
import string
''.join(random.choices(string.digits, k=8))
Avoid Possible Collision:
Try creating a new object with generated id except integrity error, create id again.
eg. -
def create_obj():
id = ''.join(random.choices(string.digits, k=8))
try:
MyModel.objects.create(id=id)
except IntegrityError:
create_obj()
OR
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)
Thanks to @WillemVanOnsem for pointing out the chances of generating duplicate id, the two examples I provided will create a new id as many times as required to get an unique id, but as the number of rows in your database increase the time to get a unique id will grow more and more and a time will come when there are so many records in your database(10^8) when creation of new record is not possible with a 8-digit uid as all possible combination already exists then you will be stuck in an infinite loop while trying to create a new object.
If the stats provided my Willem is correct, I say the changes are too high of a collision. So I would recommend not to create id's yourself, go with django's default auto field or uuid which guarantees uniqueness through space and time.

- 6,576
- 7
- 27
- 48
-
This is not guaranteed to be unique: after a while, collisions might appear. After 1000 tokens, the change of a collision is 0.05%, after 5000 tokens it is even 12%... – Willem Van Onsem Sep 21 '18 at 08:35
-
done, added codes to avoid collision with existing objects, there might be more efficient ways to do that, maybe someone else can provide a better code. – Vaibhav Vishal Sep 21 '18 at 08:48
Assuming you are using MYSQL and your comment said you didn't use database PK because they start with 1, 2...
Why not just make PK starts with your range? eg.
ALTER TABLE user AUTO_INCREMENT = 10000000;
And you can put this into your custom migration, see manage.py makemigrations --empty
I presume other databases have the similar approach as well

- 25,028
- 36
- 133
- 233
For django app I would suggest using get_random_string from django.utils.crypto package. Internally python secrets.choice is used. This way you will not have to change code, if secrets interface changes.
from django.utils.crypto import get_random_string
def generate_account_id():
return get_random_string(8, allowed_chars='0123456789')

- 1,024
- 13
- 26
If you work with python >= 3.6 , the alternative is secrets.token_hex(nbytes)
which returns string of hex value, then convert the string to number. To further detect collision you can also check whether any instance with the ID already exists in your Django model (as shown in the accepted answer)
code example :
import secrets
hexstr = secrets.token_hex(4)
your_id = int(hexstr, 16)

- 703
- 8
- 17