root/staging/: django-lockable-1.1.1 metadata and description

Homepage | Simple index | PyPI page

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
  • Development Status :: 5 - Production/Stable
  • Operating System :: OS Independent
  • Intended Audience :: Developers
  • License :: OSI Approved :: BSD License
  • Programming Language :: Python :: 3
  • Programming Language :: Python :: 3.6
  • Topic :: Software Development :: Libraries
  • Topic :: Software Development :: Libraries :: Python Modules
  • Framework :: Django
  • Framework :: Django :: 2.2
license BSD
File Tox results History
django_lockable-1.1.1-py2.py3-none-any.whl
Size
9 KB
Type
Python Wheel
Python
2.7
django_lockable-1.1.1.tar.gz
Size
9 KB
Type
Source

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