Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Progressive enhancement with Django and Backbone - how to integrate the two?

I have a very simple Django app that lets users submit a form and see a filtered list of holidays, based on country, duration and price.

I would like to use Backbone in the front-end, so that users with JS enabled don't need to GET to see results, but can load them dynamically.

I want to use progressive enhancement, so that users with JS get the Backbone experience, and users without JS can still use the form. I also want to follow the DRY principle.

My question is how best to do this. Are there examples of using the two together with minimal repetition? I'm thinking in particular of:

  1. Routing a URL like /italy/1-week/from-500-to-1000/ - do I now need to write two sets of routing code, one in Django's urls.py and one in Backbone's router, to get the country/duration/price parameters?
  2. Filtering the data, based on the parameters - do I need to write two separate ways of doing this, one in views.py and one in Backbone? (I assume I can at least use a single API for both calls.)
  3. Rendering in templates - do I need to write one list template for Django and another for Backbone, or can both use the same templates?

The best (only) example I've found of integrating Backbone into Django so far is Josh Bohde's Django Backbone repo, which is not progressively enhanced.

I've also found this blog post on progressive enhancement with Backbone and Rails, but it would be really useful to see something similar for Django.

UPDATE: Just found this SO question on a similar topic - is the situation really as hopeless as the answer makes it sound?

like image 531
Richard Avatar asked Jan 04 '13 11:01

Richard


1 Answers

is the situation really as hopeless as the answer makes it sound?

Pretty much. But, since I work on a site that used to be Django-based but is now becoming Backbone-based, I can offer a few thoughts:

Routing a URL like /italy/1-week/from-500-to-1000/ - do I now need to write two sets of routing code, one in Django's urls.py and one in Backbone's router, to get the country/duration/price parameters?

Yes, but there are ways to minimize duplication. The approach we took was to have Django spit out all the URLs as JS variables on to our main HTML page template:

<script>
URLS.report_error = "{% url app.log_client_error_view %}";
URLS.access_file = "{% url app.access_file_view 12345 %}";
</script>

Now we have a pattern of using 12345 for the parameters in every URL we generate; this makes it easy to convert that URL back in to a Backbone route regex, because we can basically replace 12345 with ([^/]+).

In the interest of full disclosure, we do have a bunch of route regexs that are written "by hand", but this isn't because we couldn't automate them; it's just that we're moving away from the Django side of things, so we have no reason to clean that code up. If you want to get hard-core about supporting both, you should be able to come up with a pretty easy/simple translation scheme.

Filtering the data, based on the parameters - do I need to write two separate ways of doing this, one in views.py and one in Backbone? (I assume I can at least use a single API for both calls.)

This is a basically unavoidable problem on any site, not just Backbone/Django. You have to filter data on the server-side because you can never trust the client-side (the user could disable JS, for instance). At the same time, server-side-only filtering is sooo 1990's, so you need to create (duplicate) logic for filtering on the client-side also (that way you can tell the user "you forgot to provide field X" without waiting for a round-trip to the server).

However, there are ways to limit this duplication. I didn't work on this piece myself, but I know a co-worker managed to use Django forms in an odd way (he took the form Django provided, then parsed them slightly before using them as a template for a Backbone View). This didn't eliminate duplication entirely, and unfortunately I can't remember any details, but it did help.

Rendering in templates - do I need to write one list template for Django and another for Backbone, or can both use the same templates?

Handlebars templates have a similar syntax to Django templates if all you're doing is variables ({{foo}}). If you want to share logic between, the two have slightly different syntax ({% if foo %} vs. {{#if foo}}), but they're close enough that if you don't mind doing a little parsing work you should easily be able to convert one in to another.

So yeah, you're taking on A LOT of work just to support a very small subset of your users (the ones with browsers that can't support Backbone). I strongly recommend you look at your user's browser stats on somewhere like Google Analytics (or look at general web stats if your site isn't up yet) to decide if all that trouble really is worth it for such a small percentage of your user base. Without statistics, you can't know how small that percentage is, and obviously a key factor in that decision.

For us the choice was obvious: require our users to use browsers made this century (which is pretty much all Backbone needs) and just go all Backbone. But if that choice isn't as obvious for you ... good luck trying to DRY up your Django and Backbone code :-)

like image 80
machineghost Avatar answered Oct 01 '22 00:10

machineghost