preamble
Originally, the title was "Generate non-repeating 4-digit numbers", but the simple numbers are a bit limited, so I'll promote it to become a non-repeating ID.
This feature was encountered while working on this small project in the image below, kind of like WeChat's face-to-face group building, where a random and non-repeating password is generated and other people can join the classroom by typing in this password.
There are quite a few ways to accomplish this, which are briefly documented in this article.
No dependency on third-party libraries
The first step is to implement this functionality purely based on Django ORM
First define a model
from import models
class MyModel():
unique_code = (max_length=4, unique=True)
single-task
The easiest and most brutal way to do this is to write a dead end loop.
import random
def generate_unique_code():
while True:
code = str((1000, 9999))
if not (unique_code=code).exists():
return code
This implementation is certainly fine in a single-threaded test environment, though the operation is not atomic and concurrent environments may generate duplicate numbers.
Consider concurrency
Database transactions or optimistic locking can be used in highly concurrent situations.
from import transaction, IntegrityError
def create_instance():
# Number of attempts
retry = 10
for _ in range(retry):
code = generate_unique_code()
try:
with ():
instance = MyModel(unique_code=code)
()
return instance
except IntegrityError:
# If a uniqueness conflict arises,retry
continue
raise Exception("Unable to generate a unique four-digit number")
pre-generated
Both of the previous methods require frequent database reads and have poorer performance.
You can also use space for time, because it's only four digits, 0000-9999 This range of numbers is not much, pre-stored the 10,000 rows into the database, add aavailable
field
When it is necessary to generate a unique ID, first filter theavailable == True
of the data, and then randomly select one; and set this field to theFalse
That's the general idea.
Using third-party libraries
In this project, I paired these three libraries (which is the main purpose of this post, to document these libraries)
- shortuuid
- hashids
- django-autoslug
shortuuid
shortuuid
is a lightweight library that generates relatively short UUIDs
It's easy to do this with this library
import shortuuid
(alphabet="0123456789").random(length=4)
But for this project, I didn't use the library for this
In fact, the library has a uuid as its name implies, and is naturally used to do work with python's built-in UUIDs
I used this library to convert theClient
Model ID simplified to 7 digits
class Client(ModelExt):
client_id = (default=uuid.uuid4, editable=False)
client_key = (max_length=100, default=uuid.uuid4)
user = (
User, on_delete=models.SET_NULL, db_constraint=False, null=True, blank=True, unique=True,
)
consumer_name = (max_length=100, null=True, blank=True)
is_online = (default=False)
def short_client_id(self):
short = (self.client_id)
return short[:7]
utilization method can turn a 32-bit UUID into a 22-bit one, and can also be used to change a 32-bit UUID into a 22-bit one using the
decode
Methodological recovery
hashids
This is a library that converts numbers to short strings
Despite the hash in its name, the library's encoding is reversible
import hashids
h = ()
(123, 456)
# Out[15]: 'X68fkp'
('X68fkp')
# Out[16]: (123, 456)
I use it to generate classroom names based on timestamps
def get_timestamp_hashid():
hashids = Hashids(salt='hahaha salt lala')
t = ().timestamp()
result = tuple(map(int, str(t).split('.')))
return (*result)
on account ofencode
method receives a number (which can also be a tuple containing a number), so here the integer and decimal parts of the timestamp are converted to tuples and passed into hashids
django-autoslug
This library is used to generate field-based unique slugs with customizable generation logic.
That's the library I use for the generate unique classroom password function (but not really recommending this approach)
from autoslug import AutoSlugField
def populate_classroom_number(instance):
return str((1000, 9999))
class ClassroomIdiom(ModelExt):
name = (max_length=100)
number = AutoSlugField(populate_from=populate_classroom_number, unique=True)
The principle of this library is very simple, according to user-defined rules to generate slug, and then check the database for duplicates, encounter duplicates, then append the number, which may result in the generation of more than 4 digits.
The best is still what I said earlierNo dependency on third-party libraries of the third way.
The use of django-autoslug here is simply a lazy way to leave the complex judgment logic to a third-party library - it's just a toy project, after all.
wrap-up
When it comes to generating unique IDs, Django is no different than any other backend framework. The idea is similar, except that you can get lazy with the Python ecosystem...