Any single-threaded program running on a machine with a finite amount of storage can be modelled as a finite state machine. A particular state in the finite state machine will represent the specific values of all relevant storage—local variables, global variables, heap storage, data currently swapped out in virtual memory, even the content of relevant files. In other words, there will be a lot of states in that finite state model, even for quite trivial programs.
Even if the only state your program has is a single global variable of a 32-bit integer type, that implies at least 2^32 (more than 4 billion) states. And that's not even taking into account the program counter and call stack.
A push-down automaton model is more realistic for this kind of thing. It's like a finite automaton, but has a built-in concept of a stack. It's not really a call-stack as in most programming languages, though.
There's a Wikipedia explanation, but don't get bogged down in the formal definition section.
Push-down automata are used to model general computations. Turing machines are similar, but IIRC not identical — though their computation capabilities are equivalent.
Thankyou to kevin cline for pointing out the error above - as Wikipedia also points out, push-down automata are more powerful than finite state machines, but less powerful than Turing machines.
I honestly don't know where this brain fart came from - I do know that context sensitive grammars are more powerful than context free, and that context sensitive grammars can't be parsed using a simple push-down automaton. I even know that while it's possible to parse any unambiguous context-free grammar in linear time, it generally takes more than a (deterministic) push-down automaton to do that. So how I could end up believing a push-down automaton is equivalent to a Turing machine is bizarre.
Maybe I was thinking of a push-down automaton with some extra machinery added, but that would be like counting a finite automaton as equivalent to a push-down automaton (just add and exploit a stack).
Push-down automata are important in parsing. I'm familiar enough with them in that context, but I have never really studied them as computer-science models of computation, so I can't give much more detail than I already have.
It is possible to model a single OOP object as finite state machine. The state of the machine will be determined by the states of all member variables. Normally, you'd only count the valid states between (not during) method calls. Again, you'll generally have a lot of states to worry about—it's something you might use as a theoretical model, but you wouldn't want to enumerate all those states, except maybe in a trivial case.
It is fairly common, though, to model some aspect of the state of an object using a finite state machine. A common case is AI for game objects.
This is also what's typically done when defining a parser using a push-down automaton model. Although there are a finite set of states in a state model, this only models part of the state of the parser—additional information is stored in extra variables alongside that state. This solves e.g. the 4-billion-states-for-one-integer issue—don't enumerate all those states, just include the integer variable. In a sense it's still part of the push-down automaton state, but it's a much more manageable approach than in effect drawing 4 billion state bubbles on a diagram.
Best Answer
I'd go one of two ways depending on the exact implementation details.
(Apologies, I'm not familiar with Django, so my answer speaks generically about the architecture and doesn't have specific suggestions for the language you're using)
1. JSON fields for data using Single Table Inheritance
As you suggested, I'd put the data in JSON(B) fields in Postgres. I'd validate by subclassing (or similar) the Tasks model using Single Table Inheritance (STI).
A quick google suggests that Django might not do STI natively, but you could get a simple enough version working by adding, say, a
type
column to your tasks table and use that to dynamically load the class that contains your validations for that type of task.Pros
Cons
2. Store validation also in JSON
Have a second table storing your task types that uses JSON schema to describe the attributes and validation of a task
Pros
Cons