Using PJAX to Speed Up a Django Web Application
Last week I started working on a new side project with my business partner @artiepatel called TimeoutDebate, an interactive sports blog and game like ESPN’s PTI (note, it’s not fully useable on iOS browsers yet). I’ve checked out PJAX and thought it would fit perfectly for this kind of content based website. Basically, it makes everything appear really snappy because all of the pages you view are loaded right into the parent page without a full page load. Sounds like ajax right? Yes, except that it pushes the actual url and all of it’s context just like a full page load sans the page load. Confused yet? Take a look at http://www.timeoutdebate.com to see it in action. Notice the lack of page loading, but the urls changing.
PJAX and Django
The good thing about PJAX is that it is really simple to get up and running… for simple stuff. There is a library called django-pjax which provides the foundation for what you need on the server-side. The rest is handled in your templates. It’s tough to know if it’s working (especially when running it locally on the devserver) so open up firebug so you can see the ajax requests being made with “_pjax=true”.
Template Re-use
Much to my horror, it looked like I needed to duplicate templates for pjax and non pjax requests. This is by design since a user can still navigate directly to a url without using a pjax request. You don’t want to leave them in the cold, but does that mean you have to maintain nearly identical templates? Here’s what I found to be effective at cutting down on the template duplication and maximize re-use.
This is my debate detail page that get’s loaded on non-pjax requests e.g. someone navigates directly to /debates/2/something-something and not via a link on the homepage.
{% extends 'index.html' %}
{% block content %}
{% comment %}Automatically re-use the pjax version of the
template to avoid duplication. This template shown if the user
reloads the browser or links direct to the content.{% endcomment %}
{% include 'debate-pjax.html' %}
{% endblock %}
I simplified this a little bit for the sake of example. I actually needed to include a script for reloading the Facebook comments section. However, this will still allow you to reuse your pjax pages even on non-pjax requests. WIN!
I also do this on the homepage to avoid the need for a index-pjax template. It’s not your typical homepage since we show you the latest sports debates instead of some static homepage bullshit.
{% block content %}
{% include 'debate-pjax.html' with debate=latest_debate %}
{% endblock %}
This is in my homepage template. When someone navigates right to timeoutdebate.com they are shown the latest news. I pass along a debate object that I rename to debate using the handy ’with’ statement inside an include tag so I can reuse the debate-pjax template again.
How the rest of TimeoutDebate works with PJAX
There is actually a lot going on in the javascript including ajaxified voting functionality, Facebook comments, and sidebar navigation. The nice thing about PJAX is that these pages are handled just like a normal view. You don’t need to do much crazy manipulation using javascript and ajax calls since you django view handles most of the variables you need right in the template.
Voting
The django view is what controls whether you can vote or not and the message returned in the modal window that pops up after a user clicks it. An ajax call posts the vote with the opinion ID and whether it’s positive or negative.
Sidebar nav
This was actually one of the trickier parts of the whole pjax experience. I needed to know what item the user was looking at and update the side nav to highlight the matching item. In the debate template I have an element that identifies what debate is loaded in the main div. I then match it to the sidebar nav item name and highlight it. I purposely have the sidebar outside of the main div where the pjax page is being pushed so that I don’t need to reload the entire nav every time someone looks at a debate.
Conclusion
PJAX has a ton of potential, but involved a lot of trial and error on my part to get it working in a dynamic web application. If the pjax request fails due to some other javascript bug there is the potential that jquery will hang the whole browser (which is TERRIBLE). There is also issues with iOS browsers, but that’s a topic for some other time. I still have a bunch of work to do to speed up TimeoutDebate, but the foundation is there. Check it out if you haven’t already!
15 Notes/ Hide
-
fergusonicd890 liked this
-
alexkehayias posted this