views:

111

answers:

2

I created a form class based on a model:

class MyModel(models.Model):
    increasing_field = models.PositiveIntegerField()

class MyForm(forms.ModelForm):
    class Meta:
        model = MyModel

I created a form to change an existing MyClass instance using POST data to populate the form:

m = MyModel.objects.get(pk=n)
f = MyForm(request.POST, instance=m)

Every time f is being updated, f.increasing_field can only be greater than the previous value.

How do I enforce that validation?

1 way I can think of is to have clean_increasing_field take on an extra argument that represents the previous value of increasing_field:

def clean_increasing_field(self, previous_value)
    ...

This way I can just make sure the new value is greater than the previous value. But it looks like clean_() methods cannot take on extra arguments.

Any ideas on how to carry out this validation?

+2  A: 

Override the constructor of your form and hold onto the previous value:

class MyForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs) # call super class
        instance = kwargs['instance']
        self.previous_value = instance.increasing_field

    def clean_increasing_field(self):
        value = self.cleaned_data['increasing_field']
        if self.previous_value >= value:
            raise forms.ValidationError, 'Increasing value can only increase'
        return value

    class Meta:
        model = MyModel

The code above assumes that you always have an instance when you instantiate the form. If you reuse the form for initial creation of a MyModel you'll have to adjust the logic in the constructor to take that into account.

Joe Holloway
With @Nick's correction, his solution is a little more simple than mine. I forgot you can access the instance via self.instance, but I'll leave my answer here because it shows how to override the constructor which comes in handy at times.
Joe Holloway
+3  A: 

Since the original model has not been updated by the time the validation is done, you could simply look at the current (unchanged) value using "self.instance.increasing_value" (or whatever your field is called). Compare this to the new value being validated, and raise an error if it's not higher than the current value.

def clean_increasing_field(self):
    new_val = self.cleaned_data['increasing_field']
    if new_val <= self.instance.increasing_field:
        raise forms.ValidationError("Increasing Field must increase!")
    return new_val   #must always return the data

Note: self.instance will return the underlying Model to which the ModelForm is bound.

Nick
Whoops that should be self.instance.increasing_field. Will fix, thanks
Nick