Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The Django UUID Story - DjangoCon US 2026

Sponsored · Ship Features Fearlessly Turn features on and off without deploys. Used by thousands of Ruby developers.

The Django UUID Story - DjangoCon US 2026

-- A talk I gave at DjangoCon US 2026

UUIDs have been part of my Django story since my first contribution to the project, when I worked on database-side RandomUUID generation for UUIDv4 generation during the sprints at DjangoCon Europe 2017 in Florence. In this talk I follow that story up to the new UUIDv7 support, showing how Django now exposes UUID generation across database backends and why newer UUID versions can be useful in real applications.

https://www.paulox.net/2026/08/26/djangocon-us-2026/

Avatar for Paolo Melchiorre

Paolo Melchiorre

August 26, 2026

More Decks by Paolo Melchiorre

Other Decks in Technology

Transcript

  1. 2

  2. 3

  3. © 2022 Bartek Pawlik (CC BY-NC-SA) Paolo Melchiorre 🔗 www.paulox.net

    󰳕 Python/Django consultant 🦄 DSF board member 🐍 PSF Fellow 🏖 Django on the Med co-founder 🐬 Python Pescara co-founder
  4. An old project 6 • 🦄 Django 1.7 • 🐍

    Python 2.7 • 🐘 PostgreSQL 9.1 • 🎫 A lot of events
  5. Two main problems 7 • 🔎 Slow like-based search *

    • 🆔 Internal IDs exposed publicly
  6. import uuid from django.db import models class Item(models.Model): ... uuid

    = models.UUIDField(default=uuid.uuid4, unique=True) 8
  7. 9

  8. 10

  9. 11

  10. 12

  11. “ … it will almost always be faster to do

    this work at lower rather than higher levels. That is, the database can typically do things faster than Python can … — Django “Performance and optimization” 13
  12. 14

  13. $ psql psql (9.5 (Ubuntu 9.5.6-0ubuntu0.16.10)) Type "help" for help.

    postgres=# SELECT GEN_RANDOM_UUID(); gen_random_uuid -------------------------------------30407da9-a807-45b4-9c54-3c61cfedea2d (1 row) 15
  14. from django.db import models class RandomUUID(modelsFunc): template = "GEN_RANDOM_UUID()" def

    __init__(self, output_field=None, **extra): if output_field is None: output_field = models.UUIDField() super().__init__(output_field=output_field, **extra) 16
  15. 19

  16. 21

  17. 23

  18. 25

  19. 29

  20. 30

  21. 31

  22. 32

  23. 33

  24. from django.contrib.postgres.functions import RandomUUID from django.db import models class Item(models.Model):

    uuid = models.UUIDField( db_default=RandomUUID(), primary_key=True ) 34
  25. BEGIN; --- Create model Item -CREATE TABLE "items_item" ( "uuid"

    uuid DEFAULT (gen_random_uuid()) NOT NULL PRIMARY KEY ); COMMIT; 35
  26. 36

  27. 37

  28. $ python Python 3.14.0~rc3-1 (main, Sep 18 2025, 14:47) [GCC

    15.2.0] on linux >>> import uuid >>> uuid.uuid7() UUID('01a02032-1baa-72c5-970a-e2686a8edccf') >>> from datetime import datetime >>> datetime.fromtimestamp(uuid.uuid7().time / 1000).isoformat() '2026-08-20T19:22:53.643000' 38
  29. 39

  30. $ psql psql (18.0 (Ubuntu 18.0-0ubuntu0.25.04.1)) postgres=# SELECT UUIDV4(); e52c3858-fa80-48f3-9b5a-5452c8efb6aa

    postgres=# SELECT UUIDV7(); 01a02ad8-0522-784b-bfc4-efaa193e6874 postgres=# SELECT uuid_extract_timestamp(UUIDV7()); 2026-08-22 21:00:31.548+02 40
  31. 44

  32. 45

  33. import datetime as dt import uuid from django.db import models

    from django.utils.functional import cached_property class Item(models.Model): uuid = models.UUIDField(default=uuid.uuid7, primary_key=True) @cached_property def creation_time(self): return dt.datetime.fromtimestamp(self.uuid.time / 1000) 47
  34. BEGIN; --- Create model Item -CREATE TABLE "items_item" ( "uuid"

    char(32) NOT NULL PRIMARY KEY ); COMMIT; 48
  35. >>> item = Item.objects.create() INSERT INTO "items_item" ("uuid") VALUES ('01a029da164d75acbf14f165d7f6ecda'::uuid)

    >>> item.uuid UUID('01a029da-164d-75ac-bf14-f165d7f6ecda') >>> item.uuid.time 1787408553549 >>> item.creation_time.isoformat() '2026-08-22T16:52:53.233000' 49
  36. from django.db import models class UUIDv7(models.Func): function = "uuidv7" output_field

    = models.UUIDField() class UUIDExtractTimestamp(models.Func): function = "uuid_extract_timestamp" output_field = models.DateTimeField() 51
  37. from django.db import models from items.functions import UUIDExtractTimestamp, UUIDv7 class

    Item(models.Model): uuid = models.UUIDField(db_default=UUIDv7(), primary_key=True) creation_time = models.GeneratedField( expression=UUIDExtractTimestamp("uuid"), output_field=models.DateTimeField(), db_persist=True, ) 52
  38. BEGIN; --- Create model Item -CREATE TABLE "items_item" ( "uuid"

    uuid DEFAULT (uuidv7()) NOT NULL PRIMARY KEY, "creation_time" timestamp with time zone GENERATED ALWAYS AS ( uuid_extract_timestamp("uuid") ) STORED ); COMMIT; 53
  39. >>> item = Item.objects.create() INSERT INTO "items_item" ("uuid") VALUES (DEFAULT)

    RETURNING "items_item"."uuid", "items_item"."creation_time" >>> item.uuid UUID('01a029da-164d-75ac-bf14-f165d7f6ecda') >>> item.uuid.time 1787408553549 >>> item.creation_time.isoformat() '2026-08-26T21:00:00.000000+00:00' 54
  40. 56

  41. 57

  42. 58

  43. from django.db import models from django.db.models.functions import UUID4, UUID7 class

    UUIDv4(models.Model): uuid = models.UUIDField(db_default=UUID4(), primary_key=True) class UUIDv7(models.Model): uuid = models.UUIDField(db_default=UUID7(), primary_key=True) 59
  44. Database support Django 6.1 60 Database Type UUID4 UUID7 PostgreSQL

    uuid ✓ ✓ (18+) MariaDB uuid (10.7+) ✓ (11.7+) ✓ (11.7+) SQLite char(32) ✓ ✓(Python 3.14+) Oracle varchar(32) ✓ (23.26.2+)* — MySQL char(32) — —
  45. Store ≠ Type ≠ Generate ≠ Default 61 • STORE

    → UUIDField • TYPE → uuid / char(32) • GENERATE → UUID4() / UUID7() • DEFAULT → default / db_default
  46. Changelog 62 • 2007 → UUID proposal (wontfix) • 2014

    → UUIDField (merged) • 2017 → RandomUUID (PostgreSQL-only) • 2022 → db_default (All fields) • 2025 → UUID4/UUID7 (All databases*)
  47. Thanks Grazie /ˈɡrat.t͡sje/ • • • • 67 Organizers Speakers

    Sponsors Volunteers © 2025 Bartek Pawlik (CC BY-NC-SA)
  48. CC License CC BY-SA 4.0 This work is licensed under

    a Creative Commons Attribution-ShareAlike 4.0 International License.