DjangoCon US 2024 was held in Durham, North Carolina from September 22–27, 2024. The conference brought together Django contributors, maintainers, and practitioners for talks spanning web development, APIs, database design, and Python ecosystem updates.
UUID Primary Keys in Django — The Status Quo
Django’s built-in UUIDField has long supported UUID primary keys using default=uuid.uuid4. This pattern is well-documented and widely used in Django projects that need globally unique identifiers without auto-increment integers.
Sessions at DjangoCon US 2024 examined the performance characteristics of this approach at scale. The core issue: uuid.uuid4() generates fully random 128-bit values. When used as a primary key in PostgreSQL or MySQL, inserts are spread randomly across the B-tree index, causing frequent page splits and a phenomenon known as index fragmentation. At tens of millions of rows, this degrades write throughput and increases index size compared to sequential keys.
Python 3.13 and the New uuid.uuid7()
A major highlight for Django developers was Python 3.13’s addition of uuid.uuid7() to the standard library. Previously, projects needed third-party packages like uuid6 to generate UUID v7 values. With Python 3.13, the function is available with no additional dependencies.
Speakers demonstrated the new usage pattern:
import uuid
from django.db import models
class MyModel(models.Model):
id = models.UUIDField(
primary_key=True,
default=uuid.uuid7,
editable=False,
)
The change from uuid.uuid4 to uuid.uuid7 is a single-token edit, and Django handles the rest: the underlying column type remains uuid, so no schema migration is needed for the database itself — only a Django migration to update the field’s default callable.
Index Performance in PostgreSQL and MySQL
Talks comparing uuid4 and uuid7 defaults measured the difference in index efficiency using pgbench and custom insert benchmarks. Findings presented were consistent with earlier research by Percona:
- UUID v4 primary keys produced ~40% more index pages than UUID v7 at equivalent row counts
- Insert throughput under concurrent load was meaningfully higher with UUID v7 due to reduced page splits
- Query performance on range scans by primary key improved significantly with UUID v7
Practical Migration from UUID v4 to UUID v7
DjangoCon US 2024 sessions provided a concrete migration checklist:
- Upgrade to Python 3.13 (or add
uuid6as a dependency for earlier versions) - Update
default=uuid.uuid4todefault=uuid.uuid7on UUID primary key fields - Run
python manage.py makemigrations— Django will generate a migration altering the field’s default - Apply the migration — no data transformation occurs; the default only affects new rows
- Optionally backfill existing rows if temporal ordering of historical data is required
Related Django and Python Resources
- Django UUIDField documentation — official reference for UUID primary keys in Django
- Python 3.13 uuid module changelog — documents the new uuid7() and uuid8() functions
- uuid6 PyPI package — UUID v7 support for Python versions before 3.13
- Percona blog on UUID performance — benchmark data on UUID v4 vs sequential IDs in MySQL
Frequently asked questions
How do Django projects handle UUID primary keys?
DjangoCon US 2024 included talks on UUID primary key strategies in Django, covering UUIDField, the move from uuid4 to uuid7 as the recommended default, and performance implications for large tables. Django's built-in UUIDField supports any UUID version.
Does Python support UUID v7?
Yes, from Python 3.13 via uuid.uuid7() in the standard library. For Python 3.9–3.12, install the uuid6 package which provides the same interface.
What column type should I use to store a UUID in a database?
Use the native type where one exists — uuid in PostgreSQL, uniqueidentifier in SQL Server. In MySQL use BINARY(16) and store raw bytes. Avoid VARCHAR(36): it costs 36 bytes per row versus 16 for binary and makes every comparison a string operation.
How do I use UUID v7 as a primary key in Django?
With Python 3.13+, use uuid.uuid7 from the standard library as the default for a UUIDField: id = models.UUIDField(primary_key=True, default=uuid.uuid7, editable=False). On earlier Python versions, the uuid6 package provides uuid6.uuid7() as a drop-in. See the Django UUIDField documentation for full details.
Does switching from UUID v4 to UUID v7 require a Django migration?
The column type stays uuid — no schema migration is needed. You only need to update the default callable on the field. Existing rows keep their UUID v4 values; new rows get UUID v7 values. Django's migration framework will detect the field change and generate a migration that alters only the default, not the column type.