Django PGLock
django-pglock provides utilities for managing PostgreSQL locks within Django applications, including advisory locks, table locks, and tools for monitoring and managing blocking locks. It is actively maintained, with regular updates to support the latest versions of Python, Django, and PostgreSQL.
Warnings
- breaking Version 1.8.0 dropped support for Python 3.9 and older Django/PostgreSQL versions, while adding support for newer ones (Python 3.14, Django 6.0, Postgres 18). Earlier versions also dropped support for older Python/Django versions.
- gotcha Advisory locks can be either session-level or transaction-level. By default, `pglock.advisory` provides a session-level lock that persists until the database session disconnects. For transaction-level locks, which are released when the transaction terminates, you must explicitly set `xact=True`.
- gotcha When using `pglock.model` to lock an entire table, it must always be executed within a database transaction. The lock is held for the duration of that transaction.
- gotcha Advisory lock IDs are global across the entire PostgreSQL database. Ensure you use unique and descriptive lock IDs (e.g., namespaced strings) to avoid unintended conflicts with other parts of your application or other applications using the same database.
- gotcha Explicit locking, especially with `pglock.model`, can increase the likelihood of deadlocks if not managed carefully. Ensure consistent lock acquisition order across concurrent operations.
Install
-
pip install django-pglock
Imports
- advisory
from pglock import advisory
- model
from pglock import model
- PGLock
from pglock.models import PGLock
- BlockedPGLock
from pglock.models import BlockedPGLock
Quickstart
import pglock
def my_exclusive_task():
# Simulate a task that should only run one instance at a time
print("Attempting to acquire lock...")
with pglock.advisory("my_critical_section_lock") as acquired:
if acquired:
print("Lock acquired! Running critical section...")
# Your critical section code here
import time
time.sleep(2)
print("Critical section complete.")
else:
print("Could not acquire lock, another instance is running.")
if __name__ == "__main__":
# In a real Django app, this would run within a Django context
# For quickstart, we just call the function directly.
# You'd typically configure Django and a database connection first.
# To test, run this script twice rapidly.
my_exclusive_task()