[Fixed]-Returning form errors for AJAX request in Django

4👍

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.

12👍

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)
👤jarred

1👍

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 }
});
👤Calvin

0👍

You can use my adjax library to handle this for you. Install the app somewhere on your path, link the adjax.js file and add add the following to your view:

import adjax
@adjax.adjax_response
def my_view(request):
    # prepare my_form with posted data as normal
    adjax.form(request, my_form)

Enable the form using javascript after loading the adjax.js file:

 $('form').adjaxify();

And enjoy 🙂

More features here: http://adjax.hardysoftware.com.au/how/ . I’ll be releasing a “1.0” version in the next week, let me know how things go. Google code project is here: http://code.google.com/p/django-adjax/

0👍

I know this is an old and answered question! Still would like to contribute. The solution I like the most is to use a decorator for methods that should error json.

import traceback,sys,simplejson

def unhandled(e):
  """
     Helper function to format an exception and it's stack
  """
  exc_type, exc_value, exc_traceback = sys.exc_info()
  lines = traceback.format_exception(exc_type, exc_value, exc_traceback)
  stack =  ''.join(line for line in lines)
  return HttpResponse(simplejson.dumps({"error":-1, "response": e.message ,"stack":stack}), content_type='application/json')


def use_json_except(f):
  def new_f(*args):
    try:
      return f(*args)
    except Exception as e:
      return unhandled(e)
    return new_f

Then you define your Django method:

 @use_json_except
 def add_annotation(request):
     ....

The decorator will catch any uncaught exceptions and output a json with the error info and the stack.

I personally find this a very good solution to a django server that mixes html and json responses.

👤fsaint

Leave a comment