{"id":3970,"library":"django-pglock","title":"Django PGLock","description":"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.","status":"active","version":"1.8.0","language":"en","source_language":"en","source_url":"https://github.com/AmbitionEng/django-pglock","tags":["django","postgresql","locking","concurrency","advisory-locks","database"],"install":[{"cmd":"pip install django-pglock","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"Core framework dependency; the library integrates directly with Django's ORM and database connections.","package":"Django","optional":false},{"reason":"PostgreSQL adapter for Python; required for Django to communicate with PostgreSQL.","package":"psycopg2-binary","optional":true}],"imports":[{"note":"Used for application-level advisory locks, as both a context manager and a decorator.","symbol":"advisory","correct":"from pglock import advisory"},{"note":"Used for locking entire Django models (tables).","symbol":"model","correct":"from pglock import model"},{"note":"Model for querying active PostgreSQL locks.","symbol":"PGLock","correct":"from pglock.models import PGLock"},{"note":"Model for querying locks that are currently blocking other activity.","symbol":"BlockedPGLock","correct":"from pglock.models import BlockedPGLock"}],"quickstart":{"code":"import pglock\n\ndef my_exclusive_task():\n    # Simulate a task that should only run one instance at a time\n    print(\"Attempting to acquire lock...\")\n    with pglock.advisory(\"my_critical_section_lock\") as acquired:\n        if acquired:\n            print(\"Lock acquired! Running critical section...\")\n            # Your critical section code here\n            import time\n            time.sleep(2)\n            print(\"Critical section complete.\")\n        else:\n            print(\"Could not acquire lock, another instance is running.\")\n\nif __name__ == \"__main__\":\n    # In a real Django app, this would run within a Django context\n    # For quickstart, we just call the function directly.\n    # You'd typically configure Django and a database connection first.\n    # To test, run this script twice rapidly.\n    my_exclusive_task()","lang":"python","description":"Demonstrates how to use `pglock.advisory` as a context manager to ensure only one instance of a critical section runs at a time. The lock ID can be any string, which `django-pglock` hashes to a 64-bit integer for PostgreSQL."},"warnings":[{"fix":"Upgrade your Python, Django, and PostgreSQL versions to match the library's requirements, or pin `django-pglock` to an older compatible version.","message":"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.","severity":"breaking","affected_versions":">=1.8.0 (Python 3.9 dropped), >=1.7.0 (Python 3.8 dropped), >=1.6.0 (Django 3.2 dropped)"},{"fix":"For transaction-level locks, use `pglock.advisory(lock_id, xact=True)`. Understand the implications: session locks can persist longer than expected if not explicitly managed, especially in connection-pooling scenarios.","message":"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`.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Wrap `pglock.model` calls within `django.db.transaction.atomic()` or similar transaction management. For example: `with transaction.atomic(): pglock.model('app_label.ModelName')`.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Use a consistent naming convention for lock IDs, such as `app_name.module_name.function_name` or `app_name.resource_id.operation`.","message":"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.","severity":"gotcha","affected_versions":"All versions"},{"fix":"Design your locking strategy to acquire locks in a consistent order whenever multiple resources are involved. Use `timeout` and `side_effect` arguments to handle contention gracefully, such as raising an error (`pglock.Raise`) or skipping execution (`pglock.Skip`) rather than waiting indefinitely.","message":"Explicit locking, especially with `pglock.model`, can increase the likelihood of deadlocks if not managed carefully. Ensure consistent lock acquisition order across concurrent operations.","severity":"gotcha","affected_versions":"All versions"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}