root/staging/: django-lockable-1.1.1 metadata and description
django-lockable provides ``Lockable``, a base django model that allow to forbid some fields to be updated
| author | Stephane "TWidi" Angel |
| author_email | s.angel@twidi.com |
| classifiers |
|
| license | BSD |
| File | Tox results | History |
|---|---|---|
django_lockable-1.1.1-py2.py3-none-any.whl
|
|
|
django_lockable-1.1.1.tar.gz
|
|
Purpose
The django-lockable app provides a Lockable model mixin allowing to “lock” a model by denying the update of its fields under certain conditions to be defined in the models using it.
About
How it works
When a model inherits from the Lockable mixin, automatically all its fields will be locked against update, as well as ManyToMany relations.
This is done, for normal fields, by an override of the attribute setter (the __setattr__ method), and for ManyToMany, by catching the m2m_changed signal (“pre*” actions).
Then, the is_field_locked method of the model is called, with the name of the field to update as argument (for a ManyToManyField that points to the current model, it will be the related_name of this field).
This method will:
- return False if the model is currently being loaded (ie during the execution of the __init__ and refresh_from_db methods)
- return False if the field is “not lockable” (see below)
- return True in all other cases (It’s here that you can override the logic)
Exclude fields
To exclude some fields from the lockable ones, simply add their name to non_lockable_fields attribute of the model. It’s a list (or other iterable), and when a field name is present in it, the is_field_locked will always return False when called with this name.
Note that this list does not need to includes fields to ignore already defined in parent classes:
class ParentModel(Lockable): field1 = models.CharField() field2 = models.CharField() non_lockable_fields = ['field2'] class ChildModel(ParentModel): field3 = models.CharField() field4 = models.CharField() non_lockable_fields = ['field4'] # ``field2`` is already included
Specific logic
To add some logic to decide when to lock or not a model, simply override is_field_locked by first calling super, and if the result is True, manage your own logic:
class MyModel(Lockable): """Example that lock the model when a flag is True.""" is_published = models.BooleanField() field = models.CharField() def is_field_locked(self, field_name): locked = super().is_field_locked(field_name) if locked: locked = self.is_published return locked
Update a locked model
In some case you may want to update a locked model, for example in a shell to debug something, or in tests.
The django_lockable.utils module provides a context manager, _no_fields_locking for this, and it’s what is used to manage the initialization of a object (__ini__ and __refresh_from_db__).
It’s really not recommended to use it in normal code as it’s in violation of the whole principle of this app. It’s why it is prefixed with a _ to mark is a private, but it’s documented because of its usefulness in some cases.
Use it this way:
# Will deactivate locking for the instance only with _no_fields_locking(instance): instance.foo = 'bar' # Will deactivate locking for all instances of the model with _no_fields_locking(MyLokableModel): instance.foo = 'bar' # Will deactivate locking for all instances of all lockable models with _no_fields_locking(Lockable): instance.foo = 'bar'
Installation
The django-lockable package is only available on the Magency private pypi server.
pip install -i https://login:password@pypi.magency.ninja/some/index django-lockable
Developement
The code can be found on the Magency mhr-python-external-modules repository
Install the required packages:
pip install -i https://login:password@pypi.magency.ninja/some/index -r requirements-dev.txt
To run tests, simply launch the runtests.sh script.
And for pylint:
PYTHONPATH="$PYTHONPATH:." pylint django_lockable tests
When ready, update the version in django_lockable/__init__py then create the package:
./setup.py sdist bdist_wheel
You can now upload it to devpi:
devpi use https://login:password@pypi.magency.ninja devpi login yourlogin devpi use yourlogin/dev devpi upload dist/django_lockable-VERSION*
Support
python>=3.4 django>=1.9