Bendegúz Csirmaz

You don't need CompositePrimaryKeys

A 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.