1

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

at14
  • 1,194
  • 9
  • 16
  • I never used it, thus I am not even attempting to provide an answer, but perhaps a signal-based logic could verify Bar and then optionally update Foo statuses? – Maciek Jan 10 '18 at 10:19

2 Answers2

1

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()
Daniel Roseman
  • 588,541
  • 66
  • 880
  • 895
  • I thought of this solution, but was wondering if there was an elegant or "magical" way of doing it automatically – at14 Jan 10 '18 at 10:40
0

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)
Milano
  • 18,048
  • 37
  • 153
  • 353
  • 1
    it's worth noting that if the Bars are being updated through queryset .update() method this will not work. – Brian H. Jan 10 '18 at 10:25