Prevents users from overwriting each others changes in Django. Forked from JoshMaker for upload to pypi.

Awesome, Django, admin, locking
pip install awesome-django-admin-locking==1.3


Awesome Django Admin Locking 1.3

Forked from: to upload to pypi

build-status-image coveralls-status-image

Prevents users from overwriting each others changes in Django.


Django Admin Locking is tested in the following environments

  • Python (2.7, 3.4)
  • Django (1.6, 1.7, 1.8, 1.9, 1.10)


Add 'locking' to your INSTALLED_APPS setting.


Add the required URL pattern:

url(r'^locking/', include('locking.urls')),


To enable locking for a ModelAdmin:

from django.contrib import admin
from locking.admin import LockingAdminMixin
from my_project.mt_models import MyModel

class MyModelAdmin(LockingAdminMixin, admin.ModelAdmin):
     pass, MyModelAdmin)

The LockingAdminMixin will automatically add a new column that displays which rows are currently locked. To manually place this column add is_locked to the admin's list_display property.

Locking Admin offers the following variables for customization in your

  • LOCKING_EXPIRATION_SECONDS - Time in seconds that an object will stay locked for without a 'ping' from the server. Defaults to 180.
  • LOCKING_PING_SECONDS - Time in seconds between 'pings' to the server with a request to maintain or gain a lock on the current form. Defaults to 15.
  • LOCKING_SHARE_ADMIN_JQUERY - Should locking use instance of jQuery used by the admin or should it use it's own bundled version of jQuery? Useful because older versions of Django do not come with a new enough version of jQuery for admin locking. Defaults to True.
  • LOCKING_DB_TABLE - Used to override the default locking table name (locking_lock)
  • LOCKING_DELETE_TIMEOUT_SECONDS - If not zero, locks will not be deleted immediately when a user leaves an admin form, but will instead be set to expire in the specified number of seconds. Specifying this setting can help avoid the following situation: a user hits 'save and continue' on a form, causing the page to reload. If locks are deleted instantly, someone else might grab the lock before the form loads again. If this value is specified, it should be set to the approximate time it takes a form to save (generally a few seconds). Defaults to 0.

Cleaning up expired locks

Overtime, you may find it necessary to remove expired locks from the database. This can be done with the following management command

$ python delete_expired_locks

If you have a non-zero specified for LOCKING_DELETE_TIMEOUT_SECONDS in your settings, you should setup a reoccurring Cron or Celery task to automatically run this management command on a regular interval.


Running the included test suite requires the following additional requirements:

  • Selenium
  • PhantomJS

JavaScript plugins for advanced widgets

By default, form field widgets are disabled by adding the attribute disabled = disabled to all inputs. If you are using a custom widget, such as a WYSIWYG editor, you may need to register a locking plugin to ensure it is correctly locked and unlocked.

Plugin registration takes the following form:

    'enable': function(form) {  /* Enabled my custom widget */ },
    'disable': function(form) {  /* Disable my custom widget */ }

For an example, look at the included plugin for the CKEditor WYSIYG editor.

Compatibility Notes

This app is compatible the popular admin theme django-grappelli


This code is licensed under the Simplified BSD License. View the LICENSE file under the root directory for complete license and copyright information.