tags:

views:

32

answers:

2

The contents of my form must be submitted to another application server for validation and execution (specifically, I call a RESTful web service with the posted values in the form). The service will either return a 200 SUCCESS or a 400/409 error with a body that describes the exact field errors.

When should I do this submission? Should I do it in the view:

if form.is_valid:
    result = submit_to_service(POST)
    if result.code in (400, 409):
        somehow_set_errors_on_the_form(form)
    else:
        go_on...

Or in the Form.clean method?

def clean(self):
    result = submit_to_service(POST)
    if result.code in (400, 409):
        for field in result.errors:
            self._errors[field].append(result.errors[field])
    else:
        pass

Which of these is clearer?

+2  A: 

validation and execution

No execution or stateful changes in the form clean(). Please. The form's clean() should only mess with data on the form, not anywhere else.

If there is a stateful change, it must be in a view function inside a non-GET request handler.

S.Lott
can you give a brief example please?
AJ
@AJ: I don't need to. Example 1 in the question -- if it occurs in a view function -- is better.
S.Lott
Got it. Thanks a lot.
AJ
S.Lott, how do you respond to Gregor's answer, below? His comment about ModelForm's `save` method seems pretty relevant.
Chris R
@Chris R: I totally disagree with that approach. The `form.save()` must not interact with outside services. The semantics of this method are clear. It has to handle a `commit=False` option properly; working with an outside service may make `commit=False` impossible to implement. The web service may make a change that is auto-committed.
S.Lott
A: 

I usually encapsulate these type of logic in the form. Since you use the form to validate the data you also use it to send the data. This makes sense because the form already knows about the data and its types etc (it has the cleaned_data dictionary).

But processing data and changing state of your application should not live directly inside your validation logic (e.g. in your clean method). You should put it in an extra method of your form - like ModelForm is doing it with the save() method.

So my suggestion is to have an extra method named save() (if the method actually saves your processing to the REST service) or post_result() or something similar that fits better.

Here is an example:

# forms.py

class ValidateDataForm(forms.Form):
    ...

    def clean(self):
        # validation logic

    def save(self):
        post_results_to_service(self.cleaned_data)

# views.py

def view(request):
    if request.method == 'POST':
        form = ValidateDataForm(request.POST)
        if form.is_valid():
            form.save()
    else:
        form = ValidateDataForm()

The above assumes that the REST service is changing state for your application, e.g. it implements some business logic. If this is not the case and you only use the service as validation for the input data on your form - and use the form data then for something different - I would suggest something different.

In this case the code should go into the clean() method like you suggested in your second code example.

Gregor Müllegger