Django Ajax Redux

Post Info

Author

Eugene Lazutkin

Date

Posted: Saturday, December 10, 2005
Updated: Sunday, December 11, 2005

Categories

Development::Python::Django (46)
Development::Web::AJAX::Dojo (32)

Three weeks ago we had a discussion about Ajax support in Django, which resulted in "Ajax and Django" wiki page. A short recap: it lists a vague goal, some general considerations, and possible strategies; it scratches the surface of existing implementations (mostly RoR), existing third-party toolkits (Mochikit/Dojo), and related RPC-style and REST-style services. No code was produced, no consensus was reached, but now it is a part of Django's Version One roadmap.

Now three weeks later I assume that everybody had time to think about it. I want to move the whole discussion on to a more practical plane. Basically I want to propose an implementation. At least I’ll collect your thoughts, criticism, corrections, and, hopefully, blessings. Giving the speculative nature of this proposal, which is based solely on my experience, I decided against posting it in the wiki in its present form. The size of this proposal is not conductive to mail list posting. Hence it is here. Saddle up.

Rationale

I am a conservative pragmatic, who values the art of possible — don’t expect any outrages proposals. And like many programmers I am quite lazy — don’t expect glorious efforts required to implement my proposal. What I want from Django Ajax implementation is:

  1. It should be realistically doable without major programming efforts.
  2. It should be loosely coupled with Django.
  3. Only Django-dependent parts should be implemented.
  4. Simple things should be simple, complex things should be possible.

The reasoning behind my criteria and related conclusions are here:

It leads to following results:

Example

Let me give you a practical example. Coincidentally it is the poster child of Ajax-enabled Web 2.0 buzzword-infested applications: autosuggest/autocomplete box. Everybody uses it in some form and fashion: Google, Del.icio.us, Amazon, Flickr, and so on. RoR‘s demos feature it prominently. Let’s admit it: it can be a useful user interface feature. It allows narrowing down your choice from practically infinite (or just huge) pool of choices. It reduces GUI clutter significantly. End users love it. Let’s examine how Django can facilitate it.

Conceptually an autosuggest box accepts user’s keyboard input and presents valid choices in pop-up overlay, one of which can be immediately selected, or it can be refined further. Of course, in real life the widget waits for a short pause (usually ~0.3s) before submitting user’s input to server. Server interprets the input and returns a list of relevant objects, which is usually bounded. This upper bound prevents server overload, limits bandwidth, and ensures that only visible items will be shown.

How does Django fit in this picture? In most cases the server component (view function) will wrap existing basic lookup functions, namely get_list() and get_values(), with proper keyword parameters. Oversimplified code can look like that:

def autosuggest_view1(user_input):
    
objects = friends.get_list(name__istartwith=user_input, limit=20)
    
return render_to_response('autosuggest_template', {'objects': objects,})

Here is more flexible approach:

def autosuggest_view2(module, search_field, user_input,
                      
search_method='istartswith', fields=None, limit=20):
    
kwargs = {
        
search_field + '__' + search_method: user_input,
        
'fields': fields,
        
'limit':  limit,
        
}
    
objects = module.get_values(**kwargs)
    
return render_to_response('autosuggest_template', {'objects': objects,})

I hope you got the drift by now. Real implementation of autosuggest view will be a specialized generic view, which may take parameters directly from GET/POST applying them after some sanity check. If you want something custom, like merging objects from two different database tables, you can do it easily in your own code — there is nothing magical about autosuggest view.

Majority of data-driven widgets are like autosuggest widget: they work with a list of objects (1D data). The only difference is the criteria of selection: it can include additional restrictions, and ranges, limit/offset combinations. Well known examples are: all kind of lists (including hierarchical lists) and tables with predefined column structure. Admittedly they are the most popular widgets. It means that my autosuggest box example covers many possible scenarios and by implementing a compact set of Django views, we can cover almost all bases.

Now there is an interesting question: how to transmit data from client to server and back? I said above indirectly that client submits parameters using standard GET/POST mechanism. It is certainly the simplest way, which works in most cases. Complex cases will require JSON. We will decide what to use on per widget basis. Autosuggest widget will be happy with GET/POST.

I propose to use AHAH as a preferred form of server-client data transfer. AHAH is a fancy name for HTML fragments. In this case we can use existing Django template mechanism to present data in the most flexible way. For example, if in your autosuggest widget you want to show nicely formatted user’s information (picture, name, position, and department) instead of plain name — just do so using Django templates. If you want to output JSON or XML, you can do it with templates too — it is not the most efficient solution, but it is as flexible as possible. Of course we can provide better implementations for such cases.

How good is AHAH? Browsers support it natively. It is the fastest way to render HTML. It is the simplest way to render HTML. For example, RoR uses it for advanced autosuggest box demo. It sends information like that:

<ul class="contacts">
    
<li class="contact">
        
<div class="image"><img src="1.jpg"/></div>
        
<div class="name">John Doe</div>
        
<div class="email"><span class="informal">john@doe.com</span></div>
    
</li>
    
<li class="contact">
        
<div class="image"><img src="2.jpg"/></div>
        
<div class="name">Jane Doe</div>
        
<div class="email"><span class="informal">jane@doe.com</span></div>
    
</li>
</ul>

This information is formatted by CSS on client side. It has regular structure making it simple to do all kind of introspections from JavaScript.

Widgets

Now when you have an idea about proposed implementation of autosuggest widget, let’s talk about other widgets and what Django Ajax needs to do to support them. The list is based on my needs and backed by existing Dojo widgets. Obviously appearance and behavior of widgets should be customizable by developers. Feel free to add/remove widgets or argue merits. Widgets are listed without any particular order.

I think that’s enough for now. I would be happy, if we implement some reasonable subset first, for example, autosuggest, calendar/date picker, paginator, WYSIWYG editor, and drag-and-drop widgets. In any case let's make Ajax version of Admin and let's make it cool and easy to use.

I can try to adapt one Dojo widget at a time. Obviously it would be faster, if somebody can help me with widgets and/or server-side components. One thing I don’t want is to waste my time. So if somebody has better ideas or found flaws in my proposal, please voice it now in django-developers. If you support the proposal, please drop a line too.

Save/recommend this post:  del.icio.us  Digg  Reddit  StumbleUpon  Facebook    Subscribe to this blog:  Bloglines  Netvibes

Most recent related documents:

Document published at about the same time:

If you want to rate this post or write a review for others to read — use the gadget in the top-right corner of the page.

Leave a comment below:

Made with Django.