Package: django-admin-page-lock
Django Admin Page LockPage Lock for Django Admin allows developers to implement customizable locking of pages.
With Admin Page Locking, only the designated (typically first) user receives their regular
permissions assigned, including edit permissions (if available for the user).
Subsequent users only get limited permissions compared to those assigned to the first user, making
sure that user will not be granted permission to edit that object while the lock is
active and owned by another user. You can store page lock data in your application's
defined database.Read more onour blog.Use Case:FirstUserlands on a page.FirstUserhas now full rights (editing), and
it's the owner of the lock.AnyOtherUsercan view the page, but cannot use full rights (no editing).FirstUserleaves the page.Whoever next enters, or refreshes, has now full rights (editing) and is the
owner of the lock.FeaturesTwo models for data storage:redisordatabase.The developer can disable whole locking functionality.Url of a page being locked can be composed with or without url parameters.History of locks can be kept (i.e. time, username).Very customizable.RequirementsDjango 1.8, 1.9, 1.11, 2.0, 2.1, 2.2;Python 2.7, 3.6, 3.7, 3.8, 3.9.InstallationEach of the following steps needs to be configured for the package to be fully functional.Getting the codeThe source code is currently hosted on GitHub at:https://github.com/Showmax/django-admin-page-lockBinary installers for the latest released version are available at thePython Package Index (PyPI).To install it using pip, just run the following:pipinstalldjango-admin-page-lockPrerequisitesMake sure to add'admin_page_lock'to yourINSTALLED_APPSsetting:INSTALLED_APPS=[# ...'admin_page_lock',]Don't forget to run./manage.py migrateor./manage.py syncdbafter this change.UsageTemplatesTo enable the Admin Page Lock you need to update the template where do you want to
have it working. The templatesbase.html,change_form.htmlandchange_list.htmlshould cover most of the use cases.On the chosen template, you have two options:Add the code bellow to the template, which gives you more freedom to customize it.{% load static %}<html><head><!-- Add the page_lock.js to the template  --><scriptsrc="{% static 'js/page_lock.js' %}"></script></head><body><!-- ...  --><divid="page_lock_bar"><divid="page_lock_message_display"></div><divid="page_lock_counter_display"></div><buttontype="button"id="page_lock_refresh_button">{% trans "REFRESH" %}</button><buttontype="button"id="page_lock_reload_button">{% trans "RELOAD" %}</button><inputtype="hidden"id="page_lock_template_data"value="{{ page_lock_template_data }}"><inputtype="hidden"id="page_lock_api_interval"value="{{ page_lock_api_interval }}"><!-- ...  --></body></html>Use the template tagspage_lock_bar_bootstraporpage_lock_bar_plain.
The javascript is added automatically when using this method.{% load page_lock_bar_bootstrap %}
...
{% page_lock_bar_bootstrap %}Disabling the locking logicTo hide locking buttons for pages where locking logic is not needed,
update the needed templates by adding the javascript block below.<scripttype="text/javascript">$(document).ready(function(){varapi_interval=parseInt($('#page_lock_api_interval').val());if(!api_interval){$('.page_lock_bar').hide();}});</script>Hiding specific html itemsAdd the classpage_lock_blockto any html tag you want to hide from users that are not
currently holding the lock. One common usage for this feature is to hide submit
buttons for users that are not holding the lock, for example:<divclass="page_lock_block"><inputtype="submit"value="Submit"/></div>ViewsViews where you want to apply the locking logic must be inherited, use:PageLockAdminMixinfor Django Admin Views;PageLockViewMixinfor Django Views.# example/models.pyfromdjango.dbimportmodelsfromadmin_page_lock.mixinsimportPageLockViewMixinclassExample(PageLockViewMixin,models.Model):...# example/admin.pyfromadmin_page_lock.mixinsimportPageLockAdminMixinfromdjango.contribimportadminfrom.modelsimportExampleclassExampleAdmin(PageLockAdminMixin,admin.ModelAdmin):...Settings parametersRe-define parameters in your settings if you don't want to use default ones:NameTypeDescriptionAPI_INTERVALintegerinterval between API calls fromjsCAN_OPEN_MORE_TABSbooleanwhether user can open one page in more tabsDISABLE_CRSF_TOKENbooleanwhether app usesCSRFprotectionDISABLEbooleanswitching off/on locking logicHANDLER_CLASSstringin case you want to define your handlerHOMEPAGEstringpage to redirect user if something goes wrongKEEP_DB_LOCKSbooleankeep locking history (only for DB model)MESSAGESdictionaryfor customizing messages (not implemented yet)TIMEOUTintegerinterval user stays on the page without refreshingMODELstringwhere data is stored (redisordatabase)REDIS_SETTINGSdictionarysettings of appredisURL_IGNORE_PARAMETERSbooleanwhether url parameters are taken into accountAPIsSeveralAPIsare listed below. These are implemented so that they can be used by both frontend (js)
and backend (python). The logic is implemented inhandlers.pyand depends on chosen model as well.At a first glance, one could think thatGetPageInfoandOpenPageConnectionare the same, but
the functionality of the first one doesn't change anything while the second one does.1. ClosePageConnectionMethodNameTypeDescriptionPOSTurlstringurl of the pagePOSTuser_referencestringreference of user (idorcurrent section)POSTcsrf_tokenstringgeneratedcsfrprotection tokenGETis_lockedbooleanwhether the page is locked2. GetPageInfoMethodNameTypeDescriptionPOSTurlstringurl of the pagePOSTuser_referencestringreference of user (idorcurrent section)POSTcsrf_tokenstringgeneratedcsfrprotection tokenGETis_lockedbooleanwhether the page is lockedGETlocked_bystringuser_reference of user locking current pageGETpage_lock_settingsdictionaryvarious parameters of settingsGETreconnectedbooleanwhether user is reconnected (not implemented yet)3. OpenPageConnectionMethodNameTypeDescriptionPOSTurlstringurl of the pagePOSTuser_referencestringreference of user (idorcurrent section)POSTcsrf_tokenstringgeneratedcsfrprotection tokenGETis_lockedbooleanwhether the page is lockedGETlocked_bystringuser_reference of user locking current pageGETpage_lock_settingsdictionaryvarious parameters of settingsGETreconnectedbooleanwhether user is reconnected (not implemented yet)TODOThere are still several functionalities missing. I would appreciate any contribution.writing unit tests;finish usingCAN_OPEN_MORE_TABSsettings parameter;migrating logic related to reopening fromOpenPageConnectionto new APIReopenPageConnection;To be implemented soon:User A lands on a page. The page is locked for this user.User B attempts to open the page.User B gets redirected to landing page (homepage, create new, and so on).UsesAtShowmax, we use this package as part of our Content Management System.