views:

31

answers:

2

In Django/Python, when you make a custom form, does it need to have a clean() method, or will calling .is_valid() perform a default validation?

if request.method == 'POST':
        filter = FilterForm(request.POST)
        if filter.is_valid():
            print 'Month is ' + filter.cleaned_data['month']
            print 'Type is ' + filter.cleaned_data['type']
            print 'Number is ' +filter.cleaned_data['number']
        else:
            print 'Invalid form'
            print filter.errors

"Invalid Form" gets printed but no errors get printed.

class FilterForm(forms.Form):
    months = [('January','January'),
                  ('February','February'),
                  ('March','March'),
                  ('April','April'),
                  ('May','May'),
                  ('June','June'),
                  ('July','July'),
                  ('August','August'),
                  ('September','September'),
                  ('October','October'),
                  ('November','November'),
                  ('December','December'),]
    types = [('text','Text'),
                 ('call','Call'),] 

    month = forms.ChoiceField(months)
    type = forms.ChoiceField(choices=types,widget=forms.CheckboxSelectMultiple)

    def __init__(self,numbers,*args, **kwargs):
        super(FilterForm,self).__init__(*args, **kwargs)
        self.fields['number'] = forms.ChoiceField(choices=numbers)

    def clean(self):
        return self.cleaned_data

I've tried it with and without the clean method.

+3  A: 

does it need to have a clean() method

No. Completely optional.

There's a big list of things that Django does in a specific order when it validates forms. You can learn about the process here:

http://docs.djangoproject.com/en/dev/ref/forms/validation/

As for finding your problem, if you stick a {{form.errors}} on your template, you'll see which field is blowing up. I have a feeling it could be that your choices is defined in a place that something can't get a handle on when it needs to (Move them out of the class).

Edit: Almost missed this. Look at this line:

def __init__(self,numbers,*args, **kwargs)

And then look at this line:

filter = FilterForm(request.POST)

You need to pass the numbers argument in this time too. It's a completely new instance. it can't validate because it doesn't know what numbers is.

Oli
I didn't think it was necessary. I'd read that page. Someone here seems to be having the same problem: http://thedjangoforum.com/board/thread/584/form-is-valid-always-returns-false/ When I print the field errors I just get an empty line so I'm not sure how to figure out what's wrong
JPC
It wouldn't let me do this filter = FilterForm(numbers=[],request.POST) or this filter = FilterForm(request.POST,numbers=[])
JPC
How about just `FilterForm([],request.POST)`?mixing args and kwargs can get messy.
Oli
+3  A: 

If you have no specific clean method, Django will still validate all the fields in your form to ensure that all required fields are present, that they have the correct type where necessary, and that fields with choices have a value corresponding to one of the choices.

There are a couple of issues with this form that could be causing your problem. Firstly, you have overridden __init__ so that the first parameter after self is numbers. However, when you instantiate the form you don't pass this parameter - you just pass request.POST.

Secondly, it's a bad idea to add fields dynamically to self.fields as you do in __init__. Instead, declare your number field with an empty choices list and just set that in __init__:

self.fields['number'].choices = numbers
Daniel Roseman
I fixed the second suggestion, thanks. I'm not sure how to deal with the first one though. When I'm posting, I say filter = FilterForm(request.POST). I thought that's how forms are supposed to work. I also need to be able to pass in a list of choices to display even if I'm not posting so I say filter = FilterForm(thelist).
JPC