Registry / web-framework / django-concurrency

django-concurrency

JSON →
library2.8.1pypypi✓ verified 84d ago

django-concurrency provides an optimistic locking mechanism for Django models, preventing concurrent editing of database records. It allows multiple users to view and attempt to edit the same record simultaneously, but only the first successful save is committed, while subsequent saves raise an error, notifying the user of the conflict. The current version is 2.8.1, actively maintained with releases tied to Django's lifecycle and Python version support.

pip install django-concurrency
INSTALL
IMPORT
SIG · DJANGO-CONCURRENCY
D
django-concurrency
web-frameworkpythonv2.8.1
Install
1.8s avg
Import
Disk
16MB
Pass rate
10/ 10
Env Coverage10 / 10
glibc
3.93.13
musl
3.93.13
Install & Compatibility
Where this runs
tested against v2.8.1 · pip install
no network on importno background threads
Install × environment matrix
Each cell = how many times install + import succeeded across repeated harness runs. Partial = flaky.
glibc = Debian/Ubuntu slim · musl = Alpine Linux
musl
py 3.103.915 runs
installs and imports cleanly · install 0.0s · import 0.000s · 18.1MB
glibc
py 3.103.915 runs
installs and imports cleanly · install 1.8s · import 0.000s · 19MB
16MB installed
● package 16MB
Code
Verified usage

Verified import paths — ran on the pinned version, not inferred.

NAME
from concurrency import NAME
from concurrency.fields import IntegerVersionField
VERSION
from concurrency import VERSION
from concurrency.fields import IntegerVersionField

This quickstart demonstrates how to add an `IntegerVersionField` to a Django model to enable optimistic locking. It shows a basic scenario where two users attempt to update the same record, and the second save correctly raises a `RecordModifiedError`, preventing data loss. Remember to add 'concurrency' to your `INSTALLED_APPS`.

import os import django from django.conf import settings from django.db import models from concurrency.fields import IntegerVersionField from concurrency.exceptions import RecordModifiedError # Minimal Django settings for a runnable example settings.configure( INSTALLED_APPS=[ 'django.contrib.auth', 'django.contrib.contenttypes', 'concurrency', # Required for django-concurrency __name__ # For models in this file ], DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3', 'NAME': ':memory:'}}, USE_TZ=True # Required by Django 3.2+ ) django.setup() class Product(models.Model): name = models.CharField(max_length=100) description = models.TextField(blank=True) version = IntegerVersionField() class Meta: app_label = __name__ # Link model to this module as an app def __str__(self): return self.name # Create tables (usually done with manage.py migrate) from django.core.management import call_command from io import StringIO out = StringIO() err = StringIO() call_command('makemigrations', __name__, interactive=False, stdout=out, stderr=err) call_command('migrate', interactive=False, stdout=out, stderr=err) # --- Usage Example --- # 1. Create a new product p = Product.objects.create(name="Original Product") print(f"Initial product: {p.name}, version: {p.version}") # 2. Simulate User A loading and modifying the product p_user_a = Product.objects.get(pk=p.pk) p_user_a.name = "Product updated by User A" p_user_a.save() print(f"User A saved: {p_user_a.name}, version: {p_user_a.version}") # 3. Simulate User B loading the product (before User A saved) # and attempting to save their changes after User A. p_user_b = Product.objects.get(pk=p.pk) # Still has version 1 from load p_user_b.name = "Product updated by User B" try: p_user_b.save() except RecordModifiedError: print(f"\nERROR: User B's save failed due to concurrency conflict!") print(f"Original version: {p_user_b.version}, current in DB: {Product.objects.get(pk=p.pk).version}") print("User B would need to reload and re-apply changes.") # Verify the final state in the database final_product = Product.objects.get(pk=p.pk) print(f"\nFinal product in DB: {final_product.name}, version: {final_product.version}")
Debug
Known issues
breakingMajor symbol renames occurred in django-concurrency 2.0. `ConcurrencyField` was moved to `concurrency.fields.IntegerVersionField`, and admin/view mixins (`ConcurrencyActionMixin`) were renamed to `ConcurrentUpdateMixin` and `ConcurrentModelAdmin`.
fix
Update import paths and class names as per official documentation or the `imports` section above. For `ConcurrencyField`, use `IntegerVersionField`.
affects: <2.0
gotchaOptimistic locking with `django-concurrency` requires explicit handling of `RecordModifiedError` in your application logic (e.g., forms, views, APIs) to inform users or re-present data for reconciliation.
fix
Wrap `save()` operations on concurrent models in `try...except RecordModifiedError` blocks and implement appropriate user feedback or retry logic.
affects: All
gotchadjango-concurrency works best for single-object updates in user-facing forms. For complex workflows involving multiple related objects or highly concurrent background processes, ensure your transaction management and error handling are robust across all affected models.
fix
Carefully design your transaction boundaries. For multi-step updates, consider using transactions and custom error handling to manage the `RecordModifiedError` across all related objects, or re-evaluate if optimistic locking is the best fit for that specific workflow.
affects: All
Upgrade
Version history
2.8.1latest on PyPI · released Apr 8, 2026
Audit
Dependencies
DjangorequiredCore framework dependency, requires Django>=3.2.
sixrequiredCompatibility layer, though mostly a no-op for modern Python versions required by this library.
Agent activity
27 hits · last 30 days
node
26
Resources
django-concurrency — pip install django-concurrency · libregistry