Learning Django by Example(3): Just works

Web September 7th, 2007

In the last post, we succeeded to post the Javascript objects via JSON to the server, the data is to be serialized to the database in this section.

Before we move on, let’s remove some bumps in our way, the database scheme is modified in this way:

class Book(models.Model):
isbn = models.CharField(maxlength=10, primary_key=True)
pub_date = models.DateField(’data published’)

The reasoning lies in that AWS returns ISBN-10 as ASIN, we may take advantage of this. Another fix is to replace DateTimeField by DateField for pub_date. Django does not support seamless database scheme refactory so far. So we just dropped the database and re-generate it as described in the tutorial. The username/password for new database is set as admin/gelman as common practice.

It is quite annoying that a 500 error returned without any reason, Django server ate the exception due to the nature of Web server. We could wrap the suspicious buggy code with try/except block like this:

try :
    // database access
except :
    print sys.exc_info()[0]

Well, InterfaceError or IntegrityError pinned the bug in database insertion, but where? Interactive shells are our best friends, you can either use pdb or python manage.py shell.

Oh, my fault, I forgot the return value of get_or_create is a tuple, instead of the object; and for many to many relation, we could not simply set a list as its value, we need to use add method after the object is constructed:

for item in simplejson.loads(request.POST[‘items’]):
        publisher, created = Publisher.objects.get_or_create(name=item[‘publisher’])
        authors = [Author.objects.get_or_create(name=au) for au in item[‘authors’]]
        authors = [author for (author, created) in authors];
        y,m,d = [int(x) for x in item[‘pub_date’].split(‘-’)]
        pub_date = date(y, m, d)
        book, created = Book.objects.get_or_create(isbn=item[‘isbn’], name=item[‘title’],
            pages=300, pub_date=pub_date, publisher=publisher)
        book.authors.add(*authors)
        #print sys.exc_info()[0]
    return HttpResponseRedirect(‘/admin/library/book/’)

At the exit, we just redirect the browser to a new URL.

It seems the database is updated, but the page is not redirected. Since the POST operation is launched in an AJAX request, we need to send JSON object as the response. In server side, simplejson.dump is used:

xhr = {’succeed’: [], ‘failed’: []};
       for item in simplejson.loads(request.POST[‘items’]):
               # … ….
               try :
                       book, created = Book.objects.get_or_create(isbn=item[‘isbn’], name=item[‘title’],
                               pages=300, pub_date=pub_date, publisher=publisher)
                       book.authors.add(*authors)
               except :
                       xhr[‘failed’].append(item[‘title’])
               xhr[’succeed’].append(item[‘title’])

       return HttpResponse(simplejson.dumps(xhr), mimetype=‘text/javascript’);

In client side, we evaluate the JSON string then populate the DOM nodes:

dojo.xhrPost({
                url: dojo.byId(“book_form”).action,
                content: { items: dojo.toJson(formdata) },
            }).addCallback(function(response) {
                var result = dojo.fromJson(response);
                var messages = dojo.query(“ul[@class=messagelist]“)[0]
                dojo.forEach(result.failed, function(item) {
                    var msg = document.createElement(“li”);
                    msg.innerHTML = “<li><em>” + item + “</em> <strong>failed</strong> to add.</li>”
                    messages.appendChild(msg);
                });
                dojo.forEach(result.succeed, function(item) {
                    var msg = document.createElement(“li”);
                    msg.innerHTML = “<em>” + item + “</em> successfully added.”
                    messages.appendChild(msg);
                });
            });

The final result looks like this:

Add books with feedback



Check r19 for details.

Learning Django by Example(2): Show me your data

Web September 5th, 2007

In last post, a quick-and-dirty prototype is developed to make Gelman running. In this post, I would tail the XSLT for our needs.

If you have not tried XSLT, consider the XSLT (for dummies and official reference). It is a powerful tool, if you only take interest data extraction, You could compare the efforts to parse XML, for example, PyAWS. The xsl is not in the repository since we need a URI to access.

Let’s keep it simpler and more stupid. Since AWS support both ISBN query and keyword search, we could combine the two input box as one and send different requests to AWS based on the knowledge of ISBN validation. Check r12 for the implementation, here is the screenshot:

Add book by search



In r14, we decided to take a try of dojo.query, an alternative of jQuery; it is really cool to reference the object using CSS syntax.

dojo.forEach(dojo.query(“#book_form input[@class=incoming]“), function(item) {
                               if (item.value != “”) {
                                       formdata.push(cache[i]);
                               }
                               i++;
                       });

In the above code snippet, cache holds the JSON objects parsed from AWS request, if an eBook file is attached to incoming(upload does not work now, just use it as the mark), the corresponding meta data is collected in formdata. The last question is how to POST the it to the server?

JSON is supported in both client and server sides, i.e dojo.json and django.utils.simplejson. In client side, we could serialize the JavaScript to JSON string:

dojo.xhrPost({
                url: dojo.byId(“book_form”).action,
                content: { items: dojo.toJson(formdata) },
            }).addCallback(function(response) {

And in server side, just loads the JSON string to Python objects. Check r16 for implementation.

items = simplejson.loads(request.POST[‘items’])

Next section, we would discuss how to manipulate the database using Django’s database API.