Skip to content

Instantly share code, notes, and snippets.

@rrafal
Last active September 21, 2023 13:15
Show Gist options
  • Save rrafal/0334dbe438ba3833a7bbcb62eae3cb24 to your computer and use it in GitHub Desktop.
Save rrafal/0334dbe438ba3833a7bbcb62eae3cb24 to your computer and use it in GitHub Desktop.
Lock PostgreSQL table in Django app
from django.db.transaction import * # NOQA
from django.utils.decorators import ContextDecorator
LOCK_MODES = (
'ACCESS SHARE',
'ROW SHARE',
'ROW EXCLUSIVE',
'SHARE UPDATE EXCLUSIVE',
'SHARE',
'SHARE ROW EXCLUSIVE',
'EXCLUSIVE',
'ACCESS EXCLUSIVE',
)
class require_lock(ContextDecorator):
"""
Decorator for PostgreSQL's table-level lock functionality
example:
@transaction.commit_on_success
@require_lock(MyModel, 'ACCESS EXCLUSIVE')
def myview(request)
...
example:
# Uses exclusive lock instead of unique index to create unique instance of a model.
def get_or_create(**kwargs):
with transaction.require_lock(MyModel, 'ACCESS EXCLUSIVE'):
return MyModel.objects.get_or_create(**kwargs)
see:
Original source code:
https://www.caktusgroup.com/blog/2009/05/26/explicit-table-locking-with-postgresql-and-django/
PostgreSQL's LOCK Documentation:
https://www.postgresql.org/docs/9.4/static/explicit-locking.html
"""
def __init__(self, model, lock):
self.db_table = model._meta.db_table
self.lock = lock
if lock not in LOCK_MODES:
raise ValueError('%s is not a PostgreSQL supported lock mode.')
def __enter__(self):
from django.db import connection
cursor = connection.cursor()
cursor.execute('LOCK TABLE %s IN %s MODE' % (self.db_table, self.lock))
def __exit__(self, exc_type, exc_value, traceback):
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment