Skip to content

Commit

Permalink
Merge branch 'master' into dont-call-hook-twice
Browse files Browse the repository at this point in the history
  • Loading branch information
rsinger86 authored Feb 14, 2021
2 parents 9732721 + c1170bf commit 100ef5e
Show file tree
Hide file tree
Showing 25 changed files with 447 additions and 278 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ README.txt
.tox
django_lifecycle.egg-info
site/
.idea/
venv/
.idea
venv
47 changes: 47 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
language: python
install:
- pip install tox
dist: xenial
sudo: required
script:
- tox
matrix:
include:
- python: 3.5
env: TOXENV=py35-django20
- python: 3.6
env: TOXENV=py36-django20
- python: 3.7
env: TOXENV=py37-django20
- python: 3.8
env: TOXENV=py38-django20
- python: 3.5
env: TOXENV=py35-django21
- python: 3.6
env: TOXENV=py36-django21
- python: 3.7
env: TOXENV=py37-django21
- python: 3.8
env: TOXENV=py38-django21
- python: 3.5
env: TOXENV=py35-django22
- python: 3.6
env: TOXENV=py36-django22
- python: 3.7
env: TOXENV=py37-django22
- python: 3.8
env: TOXENV=py38-django22
- python: 3.6
env: TOXENV=py36-django30
- python: 3.7
env: TOXENV=py37-django30
- python: 3.8
env: TOXENV=py38-django30
- python: 3.6
env: TOXENV=py36-django31
- python: 3.7
env: TOXENV=py37-django31
- python: 3.8
env: TOXENV=py38-django31
- python: 3.7
env: TOXENV=flake8
31 changes: 25 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,18 @@

[![Package version](https://badge.fury.io/py/django-lifecycle.svg)](https://pypi.python.org/pypi/django-lifecycle)
[![Python versions](https://img.shields.io/pypi/status/django-lifecycle.svg)](https://img.shields.io/pypi/status/django-lifecycle.svg/)
[![Python versions](https://img.shields.io/pypi/pyversions/django-lifecycle.svg)](https://pypi.org/project/django-lifecycle/)
![PyPI - Django Version](https://img.shields.io/pypi/djversions/django-lifecycle)

This project provides a `@hook` decorator as well as a base model and mixin to add lifecycle hooks to your Django models. Django's built-in approach to offering lifecycle hooks is [Signals](https://docs.djangoproject.com/en/dev/topics/signals/). However, my team often finds that Signals introduce unnesseary indirection and are at odds with Django's "fat models" approach.

**Django Lifecycle Hooks** supports Python 3.5, 3.6, and 3.7, Django 2.0.x, 2.1.x, 2.2.x.
This project provides a `@hook` decorator as well as a base model and mixin to add lifecycle hooks to your Django models. Django's built-in approach to offering lifecycle hooks is [Signals](https://docs.djangoproject.com/en/dev/topics/signals/). However, my team often finds that Signals introduce unnecessary indirection and are at odds with Django's "fat models" approach.

**Django Lifecycle Hooks** supports Python 3.5, 3.6, 3.7, 3.8 and 3.9, Django 2.0.x, 2.1.x, 2.2.x, 3.0.x and 3.1.x.

In short, you can write model code like this:

```python
from django_lifecycle import LifecycleModel, hook
from django_lifecycle import LifecycleModel, hook, BEFORE_UPDATE, AFTER_UPDATE


class Article(LifecycleModel):
Expand All @@ -19,16 +22,16 @@ class Article(LifecycleModel):
status = models.ChoiceField(choices=['draft', 'published'])
editor = models.ForeignKey(AuthUser)

@hook('before_update', when='contents', has_changed=True)
@hook(BEFORE_UPDATE, when='contents', has_changed=True)
def on_content_change(self):
self.updated_at = timezone.now()

@hook('after_update', when="status", was="draft", is_now="published")
@hook(AFTER_UPDATE, when="status", was="draft", is_now="published")
def on_publish(self):
send_email(self.editor.email, "An article has published!")
```

Instead of overriding `save` and `__init___` in a clunky way that hurts readability:
Instead of overriding `save` and `__init__` in a clunky way that hurts readability:

```python
# same class and field declarations as above ...
Expand Down Expand Up @@ -59,6 +62,22 @@ Instead of overriding `save` and `__init___` in a clunky way that hurts readabil

# Changelog

## 0.8.1 (January 2021)
* Added missing return to `delete()` method override. Thanks @oaosman84!

## 0.8.0 (October 2020)
* Significant performance improvements. Thanks @dralley!

## 0.7.7 (August 2020)
* Fixes issue with `GenericForeignKey`. Thanks @bmbouter!

## 0.7.6 (May 2020)
* Updates to use constants for hook names; updates docs to indicate Python 3.8/Django 3.x support. Thanks @thejoeejoee!

## 0.7.5 (April 2020)
* Adds static typed variables for hook names; thanks @Faisal-Manzer!
* Fixes some typos in docs; thanks @tomdyson and @bmispelon!

## 0.7.1 (January 2020)
* Fixes bug in `utils._get_field_names` that could cause recursion bug in some cases.

Expand Down
5 changes: 5 additions & 0 deletions django_lifecycle/__init__.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
from .django_info import IS_GTE_1_POINT_9

__version__ = "0.8.1"
__author__ = "Robert Singer"
__author_email__ = "[email protected]"


class NotSet(object):
pass


from .decorators import hook
from .mixins import LifecycleModelMixin
from .hooks import *


if IS_GTE_1_POINT_9:
Expand Down
14 changes: 2 additions & 12 deletions django_lifecycle/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,13 @@

from django_lifecycle import NotSet

from .hooks import VALID_HOOKS


class DjangoLifeCycleException(Exception):
pass


VALID_HOOKS = (
"before_save",
"after_save",
"before_create",
"after_create",
"before_update",
"after_update",
"before_delete",
"after_delete",
)


def _validate_hook_params(hook, when, when_any, has_changed):
if hook not in VALID_HOOKS:
raise DjangoLifeCycleException(
Expand Down
23 changes: 23 additions & 0 deletions django_lifecycle/hooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
BEFORE_SAVE = "before_save"
AFTER_SAVE = "after_save"

BEFORE_CREATE = "before_create"
AFTER_CREATE = "after_create"

BEFORE_UPDATE = "before_update"
AFTER_UPDATE = "after_update"

BEFORE_DELETE = "before_delete"
AFTER_DELETE = "after_delete"


VALID_HOOKS = (
BEFORE_SAVE,
AFTER_SAVE,
BEFORE_CREATE,
AFTER_CREATE,
BEFORE_UPDATE,
AFTER_UPDATE,
BEFORE_DELETE,
AFTER_DELETE
)
Loading

0 comments on commit 100ef5e

Please sign in to comment.