DEV Community

Cover image for Django Lifecycle Hooks
Eric The Coder
Eric The Coder

Posted on

Django Lifecycle Hooks

Django Lifecycle Hooks

The Python Django community is large and active. It is therefore not uncommon for quality tools to be created...

This is the case with this new Django package name Lifecycle Hook.

This package provides a @hook decorator as well as a base model and mixin to add lifecycle hooks to your Django models.

For example, we are used to doing the following with model hooks. Note how difficult to read/understand the code is:

class Article(LifecycleModel):
    contents = models.TextField()
    updated_at = models.DateTimeField(null=True)
    status = models.ChoiceField(choices=['draft', 'published'])
    editor = models.ForeignKey(AuthUser)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self._orig_contents = self.contents
        self._orig_status = self.status


    def save(self, *args, **kwargs):
        if self.pk is not None and self.contents != self._orig_contents):
            self.updated_at = timezone.now()

        super().save(*args, **kwargs)

        if self.status != self._orig_status:
            send_email(self.editor.email, "An article has published!")
Enter fullscreen mode Exit fullscreen mode

With Lifecycle Hook you can now do this:

from django_lifecycle import LifecycleModel, hook, BEFORE_UPDATE, AFTER_UPDATE


class Article(LifecycleModel):
    contents = models.TextField()
    updated_at = models.DateTimeField(null=True)
    status = models.ChoiceField(choices=['draft', 'published'])
    editor = models.ForeignKey(AuthUser)

    @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")
    def on_publish(self):
        send_email(self.editor.email, "An article has published!")
Enter fullscreen mode Exit fullscreen mode

Much much cleaner.

The package is still in beta for now but it's already working pretty well. You can learn more and try by yourself here: https://rsinger86.github.io/django-lifecycle/

Conclusion

I am convince this package will quickly become one of my favorite. It's powerfull but simple to use and make code cleaner.

I post something new almost every day so if you like post like this one you can follow-me here on dev.to

You can also follow me on Twitter: Follow @justericchapman

Top comments (1)

Collapse
 
llanilek profile image
Neil Hickman

Is this not just a rehash of Django's built-in signals? I'd be interested in seeing what performance benefits this has over signals.