Strayer
Strayer

Reputation: 3120

Set django form as erroneous after is_valid()

I need to call an API function after validating a form with is_valid(). This API call can still throw exceptions which in turn may kind of invalidate a field in the form.

How can I do that? I'm looking for something like that:

def smstrade(request):
    if request.method == "POST":
        form = SomeForm(request.POST)
        if form.is_valid():
            try:
                api_call(...)
            except SomeException:
                form["field"].set_valid(False)

Upvotes: 7

Views: 4047

Answers (4)

Anler
Anler

Reputation: 1993

In case you really want to trigger the form validation by calling is_valid a second this is the way you can do it (Django 1.4)

form = MyForm(data)
form.is_valid()
# ...
form._errors = None
form.is_valid() # trigger second validation

Upvotes: 0

Tris
Tris

Reputation: 101

Bit late, but you can invalidate the form and add display the appropriate messages by setting form._errors

>>> f.is_valid()
True
>>> f._errors['my_field'] = ['This field caused a problem']
>>> f.is_valid()
False
>>> str(f)
... <ul class="errorlist"><li>This field caused a problem</li></ul>

I needed to do this with FormView.form_valid() methods and models with unique fields

def form_valid(self, form):
  obj = User(**form.cleaned_data)
  try:
    obj.save()
  except IntegrityError:
    form._errors['username'] = ['Sorry, already taken']
    return super(MyView, self).form_invalid(form)

  return super(MyView, self).form_valid(form)

Upvotes: 10

Burhan Khalid
Burhan Khalid

Reputation: 174622

It is better to override the clean method for the field you are interested in and add your logic there. That way, you can output the appropriate error message as well.

Upvotes: 3

Sounds like you just need a variable to store a valid state outside of the form object.

def smstrade(request):
    if request.method == "POST":
        form = SomeForm(request.POST)
        valid = form.is_valid()
        if valid:
            try:
                api_call(...)
            except SomeException:
                valid = False
        if valid: # still valid?
            print "VALID!"

But really it seems like you should be putting this in the form itself, so that you only need to call is_valid() once. The only complication would be if you needed access to the request object.

class MyForm(forms.Form):
    def clean(self):
        cd = super(MyForm, self).clean()
        try:
           api_call
        except Exception:
           raise forms.ValidationError("API Call failed")
        return cd

# view..
if form.is_valid():
     print "api call success and the rest of the form is valid too."

Upvotes: 1

Related Questions