rsinger86/django-lifecycle

Order in which hooks are executed

EnriqueSoria opened this issue ยท 6 comments

Is it possible to control somehow the order in which hooks are executed?

My use case is something like this:

class Festival(LifecycleModelMixin, models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(unique=True, null=True, blank=True)

    @hook(BEFORE_CREATE)
    def set_slug(self):
        self.slug = generate_slug(self.name)

    @hook(BEFORE_CREATE)
    def do_something_with_slug(self):
        print(f"Here we want to use our slug, but it could be None: {self.slug}")

After looking into the source code I noticed that this library relies on the built-in dir to get the hooks to run. According to python docs, dir returns a list sorted alphabetically.

A possible workaround could be having a name convention on your hooks to make django-lifecycle process them in the desired order.

In your example,

class Festival(LifecycleModelMixin, models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(unique=True, null=True, blank=True)

    @hook(BEFORE_CREATE)
    def hook_1_set_slug(self):
        self.slug = generate_slug(self.name)

    @hook(BEFORE_CREATE)
    def hook_2_do_something_with_slug(self):
        print(f"Here we want to use our slug, but it could be None: {self.slug}")

Another idea: we support a "priority" kwarg to the @hook like this:

class Festival(LifecycleModelMixin, models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(unique=True, null=True, blank=True)

    @hook(BEFORE_CREATE, priorty=1)
    def set_slug(self):
        self.slug = generate_slug(self.name)

    @hook(BEFORE_CREATE, priorty=2)
    def do_something_with_slug(self):
        print(f"Here we want to use our slug, but it could be None: {self.slug}")

Another idea: we support a "priority" kwarg to the @hook like this:

class Festival(LifecycleModelMixin, models.Model):
    name = models.CharField(max_length=200)
    slug = models.SlugField(unique=True, null=True, blank=True)

    @hook(BEFORE_CREATE, priorty=1)
    def set_slug(self):
        self.slug = generate_slug(self.name)

    @hook(BEFORE_CREATE, priorty=2)
    def do_something_with_slug(self):
        print(f"Here we want to use our slug, but it could be None: {self.slug}")

That would do the trick, if you want I could try to implement it

Sounds good :)

Done, implemented in #103 ๐Ÿ˜‰

I'm closing this issue, as it has been resolved in #103.

@rsinger86 Thanks for being so nice in the code reviews, it's been a pleasure