Returning form errors for AJAX request in Django

18,211

Solution 1

Wow, it's been a year since I've seen this thread. Well, with the advent of Django 1.3 and the magical, undocumented class-based views, it's become more easy to extent Django's view related functionality. My project which makes heavy use of Django's class-based generic CRUS views need AJAX and JSON functionality. I've added an example of how I've modified Django's update view to support AJAX and return AJAX responses in the JSON format. Have a look:

def errors_to_json(errors):
    """
    Convert a Form error list to JSON::
    """
    return dict(
            (k, map(unicode, v))
            for (k,v) in errors.iteritems()
        )

class HybridUpdateView(UpdateView):
    """
    Custom update generic view that speaks JSON
    """
    def form_valid(self, form, *args, **kwargs):
        """
        The Form is valid
        """
        form.save()

        self.message = _("Validation passed. Form Saved.")
        self.data = None
        self.success = True

        payload = {'success': self.success, 'message': self.message, 'data':self.data}

        if self.request.is_ajax():
            return HttpResponse(json.dumps(payload),
                content_type='application/json',
            )
        else:
            return super(HybridUpdateView, self).form_valid(
                form, *args, **kwargs
            )

    def form_invalid(self, form, *args, **kwargs):
        """
        The Form is invalid
        """
        #form.save()

        self.message = _("Validation failed.")
        self.data = errors_to_json(form.errors)
        self.success = False

        payload = {'success': self.success, 'message': self.message, 'data':self.data}

        if self.request.is_ajax():
            return HttpResponse(json.dumps(payload),
                content_type='application/json',
            )
        else:
            return super(HybridUpdateView, self).form_invalid(
                form, *args, **kwargs
            )

The response JSON contains three fields — message (which is a human readable message), data (which is this case would be the list of form errors) and success (which is either true or false, indicating whether the request was successful or not respectively.). This is very easy to handle in jQuery client-side. A sample response looks like:

Content-Type: application/json

{"message": "Validation failed.", "data": {"host": ["This field is required."]}, "success": false}

This is just an example of how I serialized the form errors to JSON and implemented it in a class-based generic view but can be cannibalized to work with regular style views as well.

Solution 2

This question is old, but I think the shortest answer might be using simple json in a view like this.

from django.utils import simplejson

def ajax(request):
    if request.method == 'POST':
        form = someForm(request.POST)
        if form.is_valid():
            form.save()
            return HttpResponse(something)
        else:
            errors = form.errors
            return HttpResponse(simplejson.dumps(errors))
    else:
        return HttpResponse(something)

now you can access the data in your jquery like Calvin described above. Jquery makes it easy to handle the data, You could do something like this:

var errors = jQuery.parseJSON(data)
    alert(errors.username)

Solution 3

When I use front-end validation, usually the response contains chunks that you can access through dot notation (dataReturned.specificData).

Based on what and how you are returning data is the key to how to access it. The more modular you handle the data returned, the easier it is to access.

// Start ajax request to server
$.ajax({
    url: '/path_to_service',
    type: 'POST',
    data: { key: value },

    // Do something with the data
    success: function(data) {
        // Data is everything that is returned from the post
        alert(data);
        // data.message could be a piece of the entire return
        alert(data.message);
    } error: function(data) { // Handle fatal errors }
});
Share:
18,211
Mridang Agarwalla
Author by

Mridang Agarwalla

I'm a software developer who relishes authoring Java and Python, hacking on Android and toying with AppEngine. I have a penchant for development and a passion for the business side of software. In between all the work, I contribute to a number of open-source projects, learn to master the art of cooking Asian cuisine and try to stay sane while learning to fly my Align Trex-600 Nitro Heli.

Updated on June 17, 2022

Comments

  • Mridang Agarwalla
    Mridang Agarwalla almost 2 years

    I've been finding my way around Django and jQuery. I've built a basic form in Django. On clicking submit, I'm using jQuery to make an AJAX request to the sever to post my data. This bit seems to work fine and I've managed to save the data. Django returns a ValidationError when a form is invalid. Could anyone tell me how to return this set of error messages as a response to my AJAX request so I can easily iterate through it using JS and do whatever?

    I found this snippet. Looking at the JS bit (processJson) you'll see that he seems to get the error messages by extracting them from the response HTML. It seems kinda kludgy to me. Is this the best way to go about it?

    My apologies for any vagueness.

    Thanks in advance.

  • Mridang Agarwalla
    Mridang Agarwalla about 14 years
    Hi Calvin, What is considered to be a an error and what is a a success? Is there some value that i should return? On the server side, how can i return a list of validation errors as JSON so that I can list them out on the client side using the error function? This is the bit that confuses me. Thanks.
  • Calvin
    Calvin about 14 years
    Success is if what you send the service sends back data. On success is where you would manipulate the data and do something with it (usually updating a field or displaying a message). Error is if the service returns a fatal error (the service is broken or something is corrupt). Usually you would return false and do nothing but if the service is required for your thing to exists, you would tell the user the service is down. The JSON side of things is handled by your back-end service. Unfortunately my back-end skills are not quite there so I cannot tell you how to write the service.
  • bento
    bento almost 12 years
    This works. Thanks jarred. I was under the impression that you had to do a json dump of "form.errors.as_ul()" or an equivalent... but this works better. Cheers.
  • Sashko Lykhenko
    Sashko Lykhenko over 9 years
    I have syntax error in line 1, column t in data when jQuery.parseJSON(data). My data begins with Object { readyState: 4, getResponseHeader: .aj...