Django managing state of a parent model, based on "child models" (models that have a fk to the parent model)

613 Views Asked by At

Designing a a system which needs state transitions of a model which are based on transitions of other models.

I'm using Django FSM

Example:

class Foo(models.Model):
    baz = models.Charfield()

    state = FSMField(default='new')

class Bar(models.Model):
    x = models.CharField()

    state = FSMField(default='draft')

    foo = models.ForeignKey(Foo)

Use Case:

Foo can have the following states - new, draft, complete, pending_approval, approved Foo can have multiple Bars

Bar can have the following states - draft, complete

Foo should move to complete automatically when all Bar's are complete, how can this be achieved

2

There are 2 best solutions below

1
Daniel Roseman On BEST ANSWER

I don't know django-fsm at all, but with a quick look at the documentation there is a post_transition signal which is triggered after an instance changes its state. So you could define one that listens to Bar, then checks that the instance's Foo object has only completed Bars. Something like:

@receiver(post_transition, sender=Bar)
def check_completed(sender, instance, name, source, target):
    if target == 'completed':
        if not instance.foo.bar_set.filter(state='draft').exists():
            instance.foo.state = 'completed'
            instance.foo.save()
1
Milano On

Depends on use case but you can do this for example this way:

Every time, any Bar is completed, you check, whether it's Foo object has all Bars completed.

class Bar(models.Model):
    x = models.CharField()

    state = FSMField(default='draft')

    foo = models.ForeignKey(Foo)

    def save(self,*args,**kwargs):

        if not self.foo.bar_set.exclude(state='complete'):
            self.foo.state = 'complete'
            self.foo.save()
        super().save(*args,**kwargs)