Reputation: 738
I have a django model representing a task. This task will go through multiple states from 'DRAFT' to 'COMPLETION' and during that time, various fields will change from requiring user input to explicitly refusing it. For example, you can't change the date a task was completed while it's in draft. Additionally i want different links to appear on the page based on the state (i.e. if it's in checking I want the submit button to say 'Complete this task')
I originally planned for the status to be a model in it's own right but could not work out a way - beyond hard coding - that would bring any value to those models so opted for an explicit list instead. (Any better approaches here would be appreciated).
The key problem I have is how to manage these fields and their states. It seems like the easiest would be to have conditional statements in the template like {% if task.status = 'ACCEPTED' %} but that seems like putting an awful lot of business logic into a template. I also get the impression that disabling a field once you're already in a template is much harder than the form.
My current approach is to use the view to manage these states but that seems messy and doesn't (for me) solve how to change link names and the like in the template.
if task.status = Task.ACCEPTED:
form.fields['datereceived'].disabled = True
if task.status = Task.COMPLETED:
...
Is the view the place to manage these and is there a more pythonic/djangonic to manage these without overloading the template?
Sample code so excuse bugs:
Model
class Task(models.Model):
STATUS_CHOICES = (
(DRAFT, DRAFT),
(ALLOCATED, ALLOCATED),
(ACCEPTED, ACCEPTED),
(CHECKING, CHECKING),
(COMPLETED, COMPLETED),
(WITHDRAWN, WITHDRAWN),
(ON_HOLD, ON_HOLD),
)
status = models.CharField(max_length=20, choices=STATUS_CHOICES,default=DRAFT)
datereceived = models.DateField(blank=True, null=True)
dateworked = models.DateField(blank=True, null=True)
datechecked = models.DateField(blank=True, null=True)
datecompleted = models.DateField(blank=True, null=True)
datedue = models.DateField(blank=True, null=True)
Modelform
class TaskForm(forms.ModelForm):
class Meta:
model = Task
#fields = All fields listed individually but hard to pick out for sample
widgets = {
'datereceived': forms.DateInput(attrs={'class':'datepicker'}),
'datedue': forms.DateInput(attrs={'class':'datepicker'}),
'datecompleted': forms.DateInput(attrs={'class':'datepicker'}),
}
Upvotes: 1
Views: 1645
Reputation: 11
you can use finite state machine. django-fsm to handle states of your task. In this you can define the source and target state of every transition. for reference you can see this example. https://distillery.com/blog/building-for-flexibility-using-finite-state-machines-in-django/
Upvotes: 1
Reputation: 4564
Try putting the logic in the form instantiation code as so:
class TaskForm(forms.ModelForm):
class Meta:
model = Task
def handle_state(self, *args, **kwargs):
task = getattr(self, 'instance', None)
if task:
if task.status = Task.ACCEPTED:
self.fields['datereceived'].disabled = True
elif task.status = Task.COMPLETED:
...
def __init__(self, *args, **kwargs):
super(TaskForm, self).__init__(*args, **kwargs)
self.handle_state(*args, **kwargs)
Upvotes: 1