Skip to content

Commit 73f4f1a

Browse files
committed
add settings flag to allow using UUIDv7
Signed-off-by: Benjamin Skov Kaas-Hansen <[email protected]>
1 parent 95355a7 commit 73f4f1a

File tree

2 files changed

+38
-1
lines changed

2 files changed

+38
-1
lines changed

simple_history/models.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -429,8 +429,19 @@ def _get_history_id_field(self):
429429
history_id_field.primary_key = True
430430
history_id_field.editable = False
431431
elif getattr(settings, "SIMPLE_HISTORY_HISTORY_ID_USE_UUID", False):
432+
uuid_version = getattr(
433+
settings, "SIMPLE_HISTORY_HISTORY_ID_UUID_VERSION", 4
434+
)
435+
if uuid_version == 4:
436+
uuid_default = uuid.uuid4
437+
elif uuid_version == 7:
438+
uuid_default = utils.uuid7
439+
else:
440+
raise ImproperlyConfigured(
441+
"SIMPLE_HISTORY_HISTORY_ID_UUID_VERSION must be either 4 or 7"
442+
)
432443
history_id_field = models.UUIDField(
433-
primary_key=True, default=uuid.uuid4, editable=False
444+
primary_key=True, default=uuid_default, editable=False
434445
)
435446
else:
436447
history_id_field = models.AutoField(primary_key=True)

simple_history/utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
import os
2+
import time
3+
import uuid
4+
15
from django.db import transaction
26
from django.db.models import Case, ForeignKey, ManyToManyField, Q, When
37
from django.forms.models import model_to_dict
@@ -241,3 +245,25 @@ def get_change_reason_from_object(obj):
241245
return getattr(obj, "_change_reason")
242246

243247
return None
248+
249+
250+
def uuid7():
251+
"""
252+
Custom function to generate a UUIDv7 (time-based UUID) as per
253+
https://www.rfc-editor.org/rfc/rfc9562.html#name-uuid-version-7.
254+
NB! Although uuid.UUID() has a version parameter, we cannot set it to 7
255+
as of 2025-06-07 because UUID7 isn't part of the module--it it were,
256+
this function would be redundant.
257+
"""
258+
259+
# Initialise random bytearray
260+
res = bytearray(os.urandom(16))
261+
262+
# Replace first 6 bytes (= 48 bits) with timestamp values
263+
res[0:6] = (time.time_ns() // 1_000_000).to_bytes(6, "big")
264+
265+
# Then, set version and variant bits
266+
res[6] = (res[6] & 0x0F) | 0x70
267+
res[8] = (res[8] & 0x3F) | 0x80
268+
269+
return uuid.UUID(bytes=bytes(res))

0 commit comments

Comments
 (0)