Getting Django URL Patterns to Play Nicely with Angular's $routePrvider

I'm currently in the process of writing a Django project that relies heavily on AngularJS. I haven't found many tutorials on tips on how to take on such a task, but I haven't had any problems so far, at least until I wanted my URL Patterns in Django to work nicely with Angular's Routes.

The main problem with this task specifically is that both Django and Angular provide their own way of working with URLs. You'll need to satisfy Django's URL/View patterns if you're planning on having any server side logic controlled by your views, even if it's only to provide some data from your db. But you might also want to enjoy the greatness of Angular's routes, and partial HTMLs that are loaded instantly, something like Asynchronous HTML and HTTP but with real permanent links and working back button.

Note: You might want to take a look at django-pjax to get similar features only with jQuery.

So, here's the way I did it.

This is basically the code code I'm using for Angular's $routeProvider.

app.config(['$routeProvider',  function($routeProvider) {
  $routeProvider
    .when('/', {
      templateUrl: 'views/main.html',
      controller: 'MainCtrl'
    })
    .when('/about', {
      templateUrl: 'views/about.html',
    })
    .when('/help', {
      templateUrl: 'views/help.html',
    })
    .when('/post/:id', {
      templateUrl: 'views/postRouter.html',
      controller: 'PostCtrl'
    })
    .otherwise({
      redirectTo: '/'
    });
}])

Before I go through each one of these routes individually, take a look at the code I'm using in django's URLs.py for the urlpatterns.

urlpatterns = patterns('',
    url(r'^$', 'myproject.views.home', name='home'),
    url(r'^views/main.html/$', 'myproject.views.main_view'),
    url(r'^views/post.html', 'myproject.views.post_view'),
    url(r'^views/(?P[-\w]+.html)/$', 'myproject.views.angular_views'),
    url(r'^(?P.*)/$', 'myproject.views.angular_redirector'),
)

As you can notice, I'm using quite a few tricks to make this happen.

  • The 2nd and 3rd URL Patterns are also templates that Angular is using to satisfy the 1st and the 4th routes, but each one has got it's own view function because each one needs some data from database and some backend processing. The idea of the first one (views/main.html) for example is that it's loading latest posts from the db, figuring out some info about the user logged in, comments, etc..
  • But things are a bit different for the 3rd URL Pattern because this one is supposed to load data dynamically from the DB according to the post the user is loading. To share variables between Angular's routes and Django's views I bundled the values I need with the request URL of the * post * route as GET variables, this way I could load them in the view and pull the request data accordingly. The trick to do this is to route the url of "/post/:id" to a temporary html (postRouter) which has a very simple line of code:

The value of templateUrl in this template is going to be assigned in the controller PostCtrl with something like this:

app.controller('PostCtrl', ['$scope', '$routeParams', function($scope, $routeParams) {
    $scope.templateUrl = 'views/post.html?id='+$routeParams.id;
}]);

What this is essentially doing is that it's loading "views/post.html?id=postid" and passing it through Django behind the scenes, thus allowing the view function postview to do what ever it wants with the content and pass it to the actual post.html template rendering all of its django template language and loading the content according, then pass it again to Angular to view it in the assigned ng-view block.

I've tested this and worked pretty much exactly the way I wanted it to. If you've spotted anything wrong, or if you're doing it differently, please do share in the comments!

  • If you're curious about the 5th urlpattern and the angularredirector view are doing, it's just a very basic way to route coming requests to go through Angular first by adding the #/ before the url path._