Skip to main content

django-lockable provides Lockable, a base django model that allow to forbid some fields to be updated

Project description

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

Install from PyPI:

pip install django-lockable

Requirements

  • Python 3.9, 3.10, 3.11, 3.12

  • Django 4.2, 5.0, 5.1

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_lockable-1.2.1.tar.gz (67.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_lockable-1.2.1-py3-none-any.whl (9.3 kB view details)

Uploaded Python 3

File details

Details for the file django_lockable-1.2.1.tar.gz.

File metadata

  • Download URL: django_lockable-1.2.1.tar.gz
  • Upload date:
  • Size: 67.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for django_lockable-1.2.1.tar.gz
Algorithm Hash digest
SHA256 bb81c46b90aedf992bb040840a4ef6e9f19ed723ff7f0c8e925782561a9d448d
MD5 556db8e9d2a8d28603e2fc5ff180a1a5
BLAKE2b-256 09185b45ab78b0005d01751396f75b159c288f9c6d106b5ee87bf7cb124d5c1d

See more details on using hashes here.

File details

Details for the file django_lockable-1.2.1-py3-none-any.whl.

File metadata

File hashes

Hashes for django_lockable-1.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 7f5a89c3bc442ccc4e434354b4b7aba9210737c76427e857a77f64d01699ebc7
MD5 c82dc3fa66b5682c19bbc84b28e50da9
BLAKE2b-256 3cec2e83d0c2a2b997aba9224d844a727a44bb080bce9e4fb77358cbd3b80f06

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page