You don't need CompositePrimaryKeys
April 15, 2025A word of caution is in order
TL;DR
Django 5.2
ships with the new CompositePrimaryKey
class.
You should probably avoid it.
Django 5.2
The latest release of Django comes with built-in support for composite primary keys.
This has been the oldest unresolved feature request in Django for a long time and I'm proud to have contributed to resolving it.
That said, the articles, posts and docs do not seem to do a great job at explaining when you should use it.
Use Cases
In my opinion, there are 2 valid use-cases:
1. If you're connecting Django to a "legacy" database or an external database
(i.e. a database not managed by Django migrations), and this database uses composite
primary keys, use CompositePrimaryKey
for ORM support.
2. If you're using a database sharding or partitioning solution that requires composite
primary keys (e.g. Citus),
use CompositePrimaryKey
to add
composite primary keys to your database tables through Django migrations.
Personally, my use case is "multi-tenant database architecture with Citus".
When-Not-To-Use Cases
1. DO NOT use composite primary keys in place of surrogate keys
ALWAYS have a surrogate key. This can be either:
- an auto-incremented integer (
AutoField
) - a UUID (
UUIDField
) - a Nano ID, CUID or similar (
CharField
)
"Okay, but what if my database table has a natural composite key?"
My recommendation is: DON'T DO IT!
It'll make life difficult for everyone who uses your table, including yourself. Always think about:
- foreign keys
- DDL updates (what if a field is added to / removed from the composite key?)
- DML updates (what if a value changes in the composite key?)
- downstream users
In my experience, natural keys may work for simple apps, but they're not future proof and always cause a headache later down the line.
2. DO NOT use composite primary keys in place of unique constraints
It's easy to change a unique constraint, but it's hard to change a primary key because unlike unique constraints, primary keys have dependencies (e.g. foreign keys).
unique_together
and
UniqueConstraint
are perfectly fine,
don't replace them with CompositePrimaryKey
🫠
Conclusion
CompositePrimaryKey
can make life easier, but it can also make it harder.
If you don't have a good reason to use it, you should probably avoid it.
Disclaimer
This is my personal opinion and it doesn't represent the opinion of any organization I'm a part of.