Ewanw Ewanw - 1 year ago 119
Python Question

How to manage form state in django

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:


class Task(models.Model):

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)


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'}),

Answer Source

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)      
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download