django-model-subscription
Table of contents
Motivation
- Using Observer Pattern notify subscribers about changes to a django model.
- Decouple Business logic from Models.save
- Support for bulk actions (Not available using django signals.)
- Use noop subscribers when
settings.SUBSCRIPTION_RUN_EXTERNALisFalsewhich prevents having to mock subscribers that call external services in testing, local development environments. - Show changes to the instance after it has been updated i.e diff's the initial state and the current state.
Installation
$ pip install django-model-subscription
Add model_subscription to your INSTALLED_APPS
INSTALLED_APPS = [
...,
'model_subscription',
...
]
Usage
Using the SubscriptionModelMixin and SubscriptionQuerySet
from model_subscription.mixin import SubscriptionModelMixin
from model_subscription.model import SubscriptionQuerySet
class TestModel(SubscriptionModelMixin, models.Model):
name = models.CharField(max_length=255)
objects = SubscriptionQuerySet.as_manager()
Subclassing the SubscriptionModel base class.
from model_subscription.model import SubscriptionModel
class TestModel(SubscriptionModel):
name = models.CharField(max_length=255)
Creating subscribers.
- Using
OperationType
import logging
from model_subscription.decorators import subscribe
from model_subscription.constants import OperationType
log = logging.getLogger(__name__)
@subscribe(OperationType.CREATE, TestModel)
def handle_create(instance):
log.debug('Created {}'.format(instance.name))
- Using
create_subscriptiondirectly (succinct version).
import logging
from model_subscription.decorators import create_subscription
log = logging.getLogger(__name__)
@create_subscription(TestModel)
def handle_create(instance):
log.debug('Created {}'.format(instance.name))
Decorators
subscribe: Explicit (Requires a valid OperationType).
(Create, Update, Delete) operations.
create_subscription: Subscribes to create operation i.e a new instance.
@create_subscription(TestModel)
def handle_create(instance):
log.debug('1. Created {}'.format(instance.name))
update_subscription: Subscribes to updates also includes (changed_data).
@update_subscription(TestModel)
def handle_update(instance, changed_data):
log.debug('Updated {} {}'.format(instance.name, changed_data))
delete_subscription: Subscribes to delete operation:
NOTE: The instance.pk is already set to None.
@delete_subscription(TestModel)
def handle_delete(instance):
log.debug('Deleted {}'.format(instance.name))
(Bulk Create, Bulk Update, Bulk Delete) operations.
bulk_create_subscription: Subscribe to bulk create operations.
@bulk_create_subscription(TestModel)
def handle_bulk_create(instances):
for instance in instances:
log.debug('Bulk Created {}'.format(instance.name))
bulk_update_subscription: Subscribe to bulk update operations.
@bulk_update_subscription(TestModel)
def handle_bulk_update(instances):
for instance in instances:
log.debug('Updated {}'.format(instance.name))
bulk_delete_subscription: Subscribe to bulk delete operations.
@bulk_delete_subscription(TestModel)
def handle_bulk_delete(instances):
for instance in instances:
log.debug('Deleted {}'.format(instance.name))
Setup Subscribers using AppConfig.ready (Recomended).
Update you apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = 'myapp'
def ready(self):
from myapp import subscriptions
Setup Subscribers using auto discovery.
By default the settings.SUBSCRIPTION_AUTO_DISCOVER is set to False.
To use auto discovery this is not recommended as it would notify the subscribers wherever the model is used i.e IPython notebook, external scripts.
In your settings.py add
SUBSCRIPTION_AUTO_DISCOVER = True
Setting up the SUBSCRIPTION_MODULE
NOTE: This is only required when
SUBSCRIPTION_AUTO_DISCOVER = True
SUBSCRIPTION_MODULE = 'subscription'
Credits
If you feel generous and want to show some extra appreciation:
Resources
- https://python-3-patterns-idioms-test.readthedocs.io/en/latest/Observer.html
- https://refactoring.guru/design-patterns/observer
- https://hackernoon.com/observer-vs-pub-sub-pattern-50d3b27f838c
TODO's
- Supporting field level subscriptions.
- Support class based subscribers which implements
__call__ - Extend to include custom OperationType.
- Add support for using a single class to manage multiple actions i.e MyClass.update, MyClass.create.
Metadata
Release files for django-model-subscription 0.2.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| django-model-subscription-0.2.2.tar.gz | 13.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_model_subscription-0.2.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.7 kB
Release files / django-model-subscription-0.2.2.tar.gz
| Download URL | django-model-subscription-0.2.2.tar.gz |
|---|---|
| Size | 13.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a874ae344f094e9a0b800e4035f8abc4272f21c3c0596b69f0b34a01b2747eac
|
|
BLAKE2b-256 checksum How to use checksums |
84fc9943f9997527c946dc714b8d03e313b7da40f8b930608baa5cf1ea72328d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.1.9 CPython/3.7.12 Darwin/20.5.0
|
Release files / django_model_subscription-0.2.2-py3-none-any.whl
| Download URL | django_model_subscription-0.2.2-py3-none-any.whl |
|---|---|
| Size | 12.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c21bb53decbb20658c9e659306ad40bb296ab16336d3b5834387c2e5b0e130c4
|
|
BLAKE2b-256 checksum How to use checksums |
2a721717a6d6becac83064b5d9d855e6e137d110a16653a1edffe02d818740b0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
poetry/1.1.9 CPython/3.7.12 Darwin/20.5.0
|
Security for django-model-subscription 0.2.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.