django-sequences is a Python library for Django that provides a reliable way to generate gapless sequences of integer values. Unlike Django's default auto-incrementing primary keys, which can have gaps due to rolled-back transactions, this library ensures sequential integrity. It is currently at version 3.0, actively maintained, and compatible with modern Django versions (3.2 and up).
pip install django-sequencesVerified import paths — ran on the pinned version, not inferred.
To generate a gapless sequence, ensure that `get_next_value()` and the subsequent database save operation occur within the same atomic transaction. The library provides `get_next_value()` for a functional approach and a `Sequence` class for an object-oriented API. Remember to add `sequences.apps.SequencesConfig` to your `INSTALLED_APPS` and run migrations.
Always wrap your `get_next_value()` call and model creation/update in `django.db.transaction.atomic()`.
This is expected behavior and a trade-off for performance. Design your application to handle occasional internal sequence gaps if auditing the `sequences` table directly.
Minimize the amount of work performed within the `transaction.atomic()` block that calls `get_next_value()`. Consider using `nowait=True` on `get_next_value()` for non-blocking behavior, though this might raise exceptions on contention.
Use the `read committed` isolation level for optimal compatibility and guarantees. If using `repeatable read`, implement retry logic for transactions that encounter serialization errors.
Ensure all calls to `get_next_value()` and the subsequent `model.save()` are within a `with transaction.atomic():` block.
Optimize the code within the `transaction.atomic()` block to be as fast as possible. If extreme concurrency is needed and occasional non-sequential IDs are acceptable, consider alternative ID generation strategies or sharding sequences across different names.
Verify that `django.db.transaction.atomic()` strictly wraps both the `get_next_value()` call and the database `create()` or `save()` for the record that uses the generated number.