import uuid from datetime import datetime, timedelta, timezone from django.db import NotSupportedError, connection from django.db.models.functions import UUID4, UUID7 from django.test import TestCase from django.test.testcases import skipIfDBFeature, skipUnlessDBFeature from .models import UUIDModel class TestUUID(TestCase): @skipUnlessDBFeature("supports_uuid4_function") def test_uuid4(self): m1 = UUIDModel.objects.create() m2 = UUIDModel.objects.create() UUIDModel.objects.update(uuid=UUID4()) m1.refresh_from_db() m2.refresh_from_db() self.assertIsInstance(m1.uuid, uuid.UUID) self.assertEqual(m1.uuid.version, 4) self.assertNotEqual(m1.uuid, m2.uuid) @skipUnlessDBFeature("supports_uuid7_function") def test_uuid7(self): m1 = UUIDModel.objects.create() m2 = UUIDModel.objects.create() UUIDModel.objects.update(uuid=UUID7()) m1.refresh_from_db() m2.refresh_from_db() self.assertIsInstance(m1.uuid, uuid.UUID) self.assertEqual(m1.uuid.version, 7) self.assertNotEqual(m1.uuid, m2.uuid) @skipUnlessDBFeature("supports_uuid7_function_shift") def test_uuid7_shift(self): shift = timedelta(minutes=1) now = datetime.now(timezone.utc) m = UUIDModel.objects.create(uuid=UUID7(shift)) ts = int.from_bytes(m.uuid.bytes[:6]) uuid_timestamp = datetime.fromtimestamp(ts / 1000, tz=timezone.utc) self.assertAlmostEqual( (uuid_timestamp - now).total_seconds(), shift.total_seconds(), places=1 ) @skipUnlessDBFeature("supports_uuid7_function_shift") def test_uuid7_shift_duration_field(self): shift = timedelta(minutes=1) m = UUIDModel.objects.create(shift=shift) now = datetime.now(timezone.utc) UUIDModel.objects.update(uuid=UUID7("shift")) m.refresh_from_db() ts = int.from_bytes(m.uuid.bytes[:6]) uuid_timestamp = datetime.fromtimestamp(ts / 1000, tz=timezone.utc) self.assertAlmostEqual( (uuid_timestamp - now).total_seconds(), shift.total_seconds(), places=1 ) @skipIfDBFeature("supports_uuid4_function") def test_uuid4_unsupported(self): if connection.vendor == "mysql": if connection.mysql_is_mariadb: msg = "UUID4 requires MariaDB version 11.7 or later." else: msg = "UUID4 is not supported on MySQL." elif connection.vendor == "oracle": msg = "UUID4 requires Oracle version 23ai/26ai (23.9) or later." else: msg = "UUID4 is not supported on this database backend." with self.assertRaisesMessage(NotSupportedError, msg): UUIDModel.objects.update(uuid=UUID4()) @skipIfDBFeature("supports_uuid7_function") def test_uuid7_unsupported(self): if connection.vendor == "mysql": if connection.mysql_is_mariadb: msg = "UUID7 requires MariaDB version 11.7 or later." else: msg = "UUID7 is not supported on MySQL." elif connection.vendor == "postgresql": msg = "UUID7 requires PostgreSQL version 18 or later." elif connection.vendor == "sqlite": msg = "UUID7 on SQLite requires Python version 3.14 or later." else: msg = "UUID7 is not supported on this database backend." with self.assertRaisesMessage(NotSupportedError, msg): UUIDModel.objects.update(uuid=UUID7()) @skipUnlessDBFeature("supports_uuid7_function") @skipIfDBFeature("supports_uuid7_function_shift") def test_uuid7_shift_unsupported(self): msg = "The shift argument to UUID7 is not supported on this database backend." with self.assertRaisesMessage(NotSupportedError, msg): UUIDModel.objects.update(uuid=UUID7(shift=timedelta(hours=12)))