Taming ajax and django - Marc Egli and Jérémie Blaser

Tags: django, djangocon

Jérémie is a frontend developer and Marc does the backend.

Address/state handling and content rendering are the two main challenges.

Address and state handling

Problems:

  • Browser history. If you don’t watch out, the back button won’t be working.

  • Deeplinking should stay possible.

  • Crawler visibility: you want them to grab your entire site. But they don’t use javascript. So you need a special URL for them

Some solutions:

  • A hash like http://yoursite.com/#/some/id. Javascript will need to handle everything behind the hash.

    Problem: without javascript it isn’t visible. You’re invisible to crawlers. It is easy to implement, though.

  • A hashbang like http://yoursite.com/#!/some/id. The difference? Google and others replace the URL with http://yoursite.com/?_escaped_fragment_/some/id. You’ll have to configure your website to support it. Deeplinks work this way and crawlers can access the site via links in a search engine sitemap.

    It works with almost all browsers. And it covers all three mentioned problems. You have multiple URLs, however. And you’ll need to maintain legacy URLs.

    In django you could implement it with some middleware that detects the _escaped_frament_ GET parameter.

  • Pushstate. The URL is a regular URL like http://yoursite.com/some/id. The best example is the github website.

    Pro: easier to implement on the backend, good URLs, everything crawlable and deeplinkable. It degrades gracefully.

    Drawbacks: no wide support. Even IE9 doesn’t support it. 62% of the now-used-browser-clients support it. But… it does work, just slower, as you need to grab a whole new page. Another drawback: it is more work for the frontend developer.

Their approach

They do it with pjax: Push state ajax. A pjax link fetches the whole new page source over ajax and extracts a specified div and the title and modifies the browser history. You improve the speed this way by not needing to re-render the entire page, only one part is updated.

There are some existing implementations, like django-jax, django-easy-pjax and django-ajax-blocks, but they all had problems. So they made their own solution:

  • Django: template inheritance and filters and middleware.

  • Backbone.js

They have two base templates: one for the regular layout and one for the pjax responses. They build a template filter “pjax” that returns whether it is a pjax request or not and modifies the name of the template that’s extended. That way you get a mostly empty page for pjax and the full one for regular requests.

Backbone handles the pjax handling, requesting the new page and replacing divs and so. And it keeps track of the browser history.

Some pitfalls: caching and redirection.

  • You use the same URL for your regular and pjax response. So caching can trip you up. Setting a Vary header helps, but not in all browsers. So they’re now using a special URL and modify it back to the original URL in middleware.

  • Redirections happen transparently for ajax requests. You don’t have a chance to intercept them. To work around it, they return json for pjax requests with the redirect info in there.

Content rendering

Client site templates can make your site faster. It would be nice to use the same template on the server and client side. They’re using https://github.com/chrisdickinson/plate, which aims to be mostly compatible with Django’s template language.

 
vanrees.org logo

Reinout van Rees

My name is Reinout van Rees and I program in Python, I live in the Netherlands, I cycle recumbent bikes and I have a model railway.

Weblog feeds

Most of my website content is in my weblog. You can keep up to date by subscribing to the automatic feeds (for instance with Google reader):