Oct 18, 2009

django-piston form validation -- part 3

In my previous post titled "Exploration of django-piston -- part 2" [1] I end the post by 2 open issues. This post will propose a solution to the first one:

The validation errors are returned as a pseudo xml string.


Bad Request <ul class="errorlist"><li>content<ul class="errorlist"><li>This field is required.</li></ul></li><li>title<ul class="errorlist"><li>This field is required.</li></ul></li></ul>


To put it in other words I would prefer if django-piston return the validation errors of the form in the format specified in the request.

JSON


$ curl -u testuser:foobar -X POST -d content="This post is created using the api" http://127.0.0.1:8000/api/posts/?format=json
Bad Request {"title": ["This field is required."]}


yaml

$ curl -u testuser:foobar -X POST -d content="This post is created using the api" http://127.0.0.1:8000/api/posts/?format=yaml
Bad Request title: [!!python/unicode 'This field is required.']

xml


$ curl -u testuser:foobar -X POST -d content="This post is created using the api" http://127.0.0.1:8000/api/posts/?format=xml
Bad Request <ul class="errorlist"><li>title<ul class="errorlist"><li>This field is required.</li></ul></li></ul>


After a while reading the source of django-piston and poking around I have implemented this feature in my branch.

The biggest hurdle was that for some reasons "form.errors" cannot be serialized directly.


simplejson.dumps(form.errors)
*** TypeError:  is not JSON serializable


In order to work around this issue you need to force python to evaluate this proxy object.


dict((key, [unicode(v) for v in values]) for key,values in form.errors.items())


The last bit is to change the JS in order to adapt it to the fact that now the validation errors are returned as a json string.


    response = response.substring(12, response.length);
    errors = eval("("+response+")");

    $.each($(':input'), function(index, value) {
        field =$(value).attr('id');
        field = field.substring(3, field.length);
        field_errors = errors[field];
        if (field_errors) {
            ul = "<ul class=\"errorlist\">\n";
            $.each(field_errors, function(index, value){
              ul += "<li>"+value+"</li>\n";
            });
            ul += "</ul>\n";
            $(value).parent().prepend(ul);
        };
    });

The complete code related to the implementation of this feature is available in my branch [3].

Open Issue

Authentication is still hardcoded into the html pages. What is the best way to keep HttpBasicAuthentication to the external api that could easily be used by curl and add single sign on with django admin interface ?

The example is still very incomplete. It is missing among other things the capability to update/delete a blog post

I would be glad to read from you on how to improve this example or to get pointer of reusable application that have been built on top of django-piston.


[1] http://yml-blog.blogspot.com/2009/10/exploration-of-django-piston-part-2.html
[2] http://bitbucket.org/yml/django-piston/changeset/a8bcb7f9756e/
[3] http://bitbucket.org/yml/django-piston/
blog comments powered by Disqus