# django-triggers [![Latest Version][latest-version-image]][latest-version-link]
[![Test Status][test-status-image]][test-status-link]
[![codecov][codecov-image]][codecov-link]
[![Python Support][python-support-image]][python-support-link]
`django-triggers` is intended for implementing event-based business logic configurable through the Django admin site.
## Install
```shell
pip install dj-triggers
```
```python
INSTALLED_APPS = [
...
"polymorphic",
"triggers",
...
]
```
### Prerequisites
Celery is required to be setup in your project.
## Quickstart
Let's consider a simple tasks app with a model `Task` and we want to email a user when a task is completed.
1. Add event, action and condition models into your app's models.py
By doing this, we separate the development of the trigger components from their configuration within the Django admin panel. This ensures a more modular and manageable approach to building and configuring triggers.
The full code example is available in [tests directory](https://github.com/cockpithq/django-triggers/tree/main/tests/app).
```python
from django.dispatch import receiver, Signal
from django.contrib.auth.models import User
from django.db import models, transaction
from triggers.models import Action, Event
# Our domain model
class Task(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
name = models.CharField(max_length=128)
is_completed = models.BooleanField(default=False, db_index=True, editable=False)
is_important = models.BooleanField(default=False)
completed = Signal()
def complete(self):
if not self.is_completed:
self.is_completed = True
self.save()
transaction.on_commit(lambda: self.completed.send(sender=self.__class__, task=self))
# At first, implement an Event which will trigger the notification.
class TaskCompletedEvent(Event):
# By setting the following `important_only` field through the Django admin site
# we can configure what tasks (all or important only) we want to notify the users about.
important_only = models.BooleanField(
default=False,
help_text='Fire the event for important tasks only if checked.',
)
def should_be_fired(self, **kwargs) -> bool:
if self.important_only:
return Task.objects.filter(id=kwargs['task_id'], is_important=True).exists()
return True
# Then we need to fire `TaskCompletedEvent` when a task is marked as completed.
@receiver(Task.completed)
def on_task_completed(sender, task: Task, **kwargs):
for event in TaskCompletedEvent.objects.all():
transaction.on_commit(lambda: event.fire_single(task.user_id, task_id=task.id))
# At the end, create an Action implementing email notification.
class SendEmailAction(Action):
subject = models.CharField(max_length=256)
message = models.TextField()
def perform(self, user: User, context: Dict[str, Any]):
user.email_user(self.subject, self.message)
```
2. Makemigrations and migrate
```shell
python manage.py makemigrations
python manage.py migrate
```
3. Add trigger on the Django admin site
Don't forget to enable it :)
<img width="557" alt="SCR-20230315-sooo" src="https://user-images.githubusercontent.com/101798/225434592-db566401-873a-4698-9292-79e51ddec5ee.png">
4. Use the trigger!
```python
task = Task.objects.get(id=...) # Get your task
task.complete() # And mark it as completed
```
You may also trigger it manually from the Django admin site if you're checking the test app example.
<img width="369" alt="image" src="https://user-images.githubusercontent.com/101798/225565474-8d594a19-03b7-4501-b995-d66f45acdf64.png">
## Development
### Run a django-admin command, e.g. `makemigrations`
```shell
poetry run python -m django makemigrations --settings=tests.app.settings
```
### Run isort
```shell
poetry run isort triggers tests
```
### Run flake8
```shell
poetry run flake8 triggers tests
```
### Run mypy
```shell
poetry run mypy triggers tests
```
### Run pytest
```shell
poetry run pytest
```
[latest-version-image]: https://img.shields.io/pypi/v/dj-triggers.svg
[latest-version-link]: https://pypi.org/project/dj-triggers/
[codecov-image]: https://codecov.io/gh/cockpithq/django-triggers/branch/main/graph/badge.svg?token=R5CG3VJI73
[codecov-link]: https://codecov.io/gh/cockpithq/django-triggers
[test-status-image]: https://github.com/cockpithq/django-triggers/actions/workflows/test.yml/badge.svg
[test-status-link]: https://github.com/cockpithq/django-triggers/actions/workflows/test.yml
[python-support-image]: https://img.shields.io/pypi/pyversions/dj-triggers.svg
[python-support-link]: https://pypi.org/project/dj-triggers/
Raw data
{
"_id": null,
"home_page": "https://github.com/cockpithq/django-triggers",
"name": "dj-triggers",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7,<4.0",
"maintainer_email": "",
"keywords": "django,triggers",
"author": "Dmitry Kolyagin",
"author_email": "dmitry.kolyagin@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/85/03/127beb3bde4355218251d4ed4b09a8d75b22f420c31679e7f9f29bf13b61/dj_triggers-1.0.1.tar.gz",
"platform": null,
"description": "# django-triggers [![Latest Version][latest-version-image]][latest-version-link]\n[![Test Status][test-status-image]][test-status-link]\n[![codecov][codecov-image]][codecov-link]\n[![Python Support][python-support-image]][python-support-link]\n\n`django-triggers` is intended for implementing event-based business logic configurable through the Django admin site.\n\n## Install\n\n```shell\npip install dj-triggers\n```\n\n```python\nINSTALLED_APPS = [\n ...\n \"polymorphic\",\n \"triggers\",\n ...\n]\n```\n\n\n### Prerequisites \n\nCelery is required to be setup in your project.\n\n## Quickstart\n\nLet's consider a simple tasks app with a model `Task` and we want to email a user when a task is completed.\n\n1. Add event, action and condition models into your app's models.py\n\nBy doing this, we separate the development of the trigger components from their configuration within the Django admin panel. This ensures a more modular and manageable approach to building and configuring triggers.\n\nThe full code example is available in [tests directory](https://github.com/cockpithq/django-triggers/tree/main/tests/app).\n```python\nfrom django.dispatch import receiver, Signal\nfrom django.contrib.auth.models import User\nfrom django.db import models, transaction\n\nfrom triggers.models import Action, Event\n\n\n# Our domain model\nclass Task(models.Model):\n user = models.ForeignKey(User, on_delete=models.CASCADE)\n name = models.CharField(max_length=128)\n is_completed = models.BooleanField(default=False, db_index=True, editable=False)\n is_important = models.BooleanField(default=False)\n\n completed = Signal()\n\n def complete(self):\n if not self.is_completed:\n self.is_completed = True\n self.save()\n transaction.on_commit(lambda: self.completed.send(sender=self.__class__, task=self))\n\n\n# At first, implement an Event which will trigger the notification.\nclass TaskCompletedEvent(Event):\n # By setting the following `important_only` field through the Django admin site \n # we can configure what tasks (all or important only) we want to notify the users about.\n important_only = models.BooleanField(\n default=False, \n help_text='Fire the event for important tasks only if checked.',\n ) \n\n def should_be_fired(self, **kwargs) -> bool:\n if self.important_only:\n return Task.objects.filter(id=kwargs['task_id'], is_important=True).exists()\n return True\n\n\n# Then we need to fire `TaskCompletedEvent` when a task is marked as completed.\n@receiver(Task.completed)\ndef on_task_completed(sender, task: Task, **kwargs):\n for event in TaskCompletedEvent.objects.all():\n transaction.on_commit(lambda: event.fire_single(task.user_id, task_id=task.id))\n\n\n# At the end, create an Action implementing email notification.\nclass SendEmailAction(Action):\n subject = models.CharField(max_length=256)\n message = models.TextField()\n\n def perform(self, user: User, context: Dict[str, Any]):\n user.email_user(self.subject, self.message)\n```\n\n2. Makemigrations and migrate\n```shell\npython manage.py makemigrations\npython manage.py migrate\n```\n\n3. Add trigger on the Django admin site\n\nDon't forget to enable it :)\n\n<img width=\"557\" alt=\"SCR-20230315-sooo\" src=\"https://user-images.githubusercontent.com/101798/225434592-db566401-873a-4698-9292-79e51ddec5ee.png\">\n\n4. Use the trigger!\n\n```python\ntask = Task.objects.get(id=...) # Get your task\ntask.complete() # And mark it as completed\n```\n\nYou may also trigger it manually from the Django admin site if you're checking the test app example.\n\n<img width=\"369\" alt=\"image\" src=\"https://user-images.githubusercontent.com/101798/225565474-8d594a19-03b7-4501-b995-d66f45acdf64.png\">\n\n## Development\n\n### Run a django-admin command, e.g. `makemigrations`\n```shell\npoetry run python -m django makemigrations --settings=tests.app.settings\n```\n\n### Run isort\n```shell\npoetry run isort triggers tests\n```\n### Run flake8\n```shell\npoetry run flake8 triggers tests\n```\n### Run mypy\n```shell\npoetry run mypy triggers tests\n```\n### Run pytest\n```shell\npoetry run pytest\n```\n\n[latest-version-image]: https://img.shields.io/pypi/v/dj-triggers.svg\n[latest-version-link]: https://pypi.org/project/dj-triggers/\n[codecov-image]: https://codecov.io/gh/cockpithq/django-triggers/branch/main/graph/badge.svg?token=R5CG3VJI73\n[codecov-link]: https://codecov.io/gh/cockpithq/django-triggers\n[test-status-image]: https://github.com/cockpithq/django-triggers/actions/workflows/test.yml/badge.svg\n[test-status-link]: https://github.com/cockpithq/django-triggers/actions/workflows/test.yml\n[python-support-image]: https://img.shields.io/pypi/pyversions/dj-triggers.svg\n[python-support-link]: https://pypi.org/project/dj-triggers/\n",
"bugtrack_url": null,
"license": "BSD-3-Clause",
"summary": "A Triggers system for Django made for implementing event-based business logic configurable through the Django admin site.",
"version": "1.0.1",
"split_keywords": [
"django",
"triggers"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "1cb80f15c1e4e5fceefc254c68be9f02640ac0098051d73035097d36acd8d59a",
"md5": "bd5f6fcad29083e3f7e9c8ca7b1bca92",
"sha256": "2e8c24d9bef43209c8a04518f122e35aa9f70382e7da217ebff78927387e1ea9"
},
"downloads": -1,
"filename": "dj_triggers-1.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "bd5f6fcad29083e3f7e9c8ca7b1bca92",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7,<4.0",
"size": 11193,
"upload_time": "2023-03-18T05:59:05",
"upload_time_iso_8601": "2023-03-18T05:59:05.690407Z",
"url": "https://files.pythonhosted.org/packages/1c/b8/0f15c1e4e5fceefc254c68be9f02640ac0098051d73035097d36acd8d59a/dj_triggers-1.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8503127beb3bde4355218251d4ed4b09a8d75b22f420c31679e7f9f29bf13b61",
"md5": "fe107c405230ab250a7d23dda3daa490",
"sha256": "8263c3e6c1d9a8e3cce4052325e4e5e22f9211d1ebb8c24f367295b2c5834f1b"
},
"downloads": -1,
"filename": "dj_triggers-1.0.1.tar.gz",
"has_sig": false,
"md5_digest": "fe107c405230ab250a7d23dda3daa490",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7,<4.0",
"size": 10233,
"upload_time": "2023-03-18T05:59:07",
"upload_time_iso_8601": "2023-03-18T05:59:07.329212Z",
"url": "https://files.pythonhosted.org/packages/85/03/127beb3bde4355218251d4ed4b09a8d75b22f420c31679e7f9f29bf13b61/dj_triggers-1.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2023-03-18 05:59:07",
"github": true,
"gitlab": false,
"bitbucket": false,
"github_user": "cockpithq",
"github_project": "django-triggers",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "dj-triggers"
}