17

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.

5 Answers 5

13

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)
Sign up to request clarification or add additional context in comments.

2 Comments

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.
I have syntax error in line 1, column t in data when jQuery.parseJSON(data). My data begins with Object { readyState: 4, getResponseHeader: .aj...
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.

Comments

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

2 Comments

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.
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.
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/

Comments

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.