Manage Django URLs for AngularJS

AngularJS controllers communicating with the Django application through Ajax, often require URLs, pointing to some of the views of your application. Don’t fall into temptation to hard code such a URL into the client side controller code. Even worse would be to create Javascript dynamically using a template engine. There is a clean and simple solution to solve this problem.

Note

Until version 0.7 django-angular reversed all existing URLs of a project and created an object exposing them to Javascript. Documentation for now deprecated approach is available here.

Starting with version 0.8, django-angular provides a new way to handle URLs, which offers the reversing functionality directly to AngularJS modules.

This service is provided by djangoUrl.reverse(name, args_or_kwargs) method. It behaves exactly like Django’s URL template tag.

Basic operation principle

django-angular encodes the parameters passed to djangoUrl.reverse() into a special URL starting with /angular/reverse/.... This URL is used as a new entry point for the real HTTP invocation.

Installation

Angular

  • Include django-angular.js:
<script src="{% static 'djangular/js/django-angular.js' %}"></script>
  • Add ng.django.urls as a dependency for you app:
<script>
    var my_app = angular.module('MyApp', ['ng.django.urls', /* other dependencies */]);
</script>

The djangoUrl service is now available through dependency injection to all directives and controllers.

Setting via Django Middleware

  • Add 'djangular.middlewares.DjangularUrlMiddleware' to MIDDLEWARE_CLASSES in your Django

settings.py file:

MIDDLEWARE_CLASSES = (
    'djangular.middleware.DjangularUrlMiddleware',
    # Other middlewares
)

Warning

This must be the first middleware included in MIDDLEWARE_CLASSES

Using this approach adds some magicness to your URL routing, because the DjangularUrlMiddleware class bypasses the HTTP request from normal URL resolving and calls the corresponding view function directly.

Alternative settings via Django urlconfig

  • Add url(r'^angular/', include('djangular.urls')) to your main urls.py file:
urlpatterns = patterns('',
    ...
    url(r'^angular/', include('djangular.urls')),
    ...
)

Using this approach adds another layer of redirection, because Ajax requests first are resolved into the real URL sent back to the client using a HTTP permanent redirect response. This second (redirected) request, then is send as the real URL, which is resolved by Django in the usual manner.

Warning

Either use the setting via middleware or via urlconfig, but never both.

Usage

The reversing functionality is provided by:

djangoUrl.reverse(name, args_or_kwargs)

This method behaves exactly like Django’s URL template tag {% url 'named:resource' %}.

Parameters

  • name: The URL name you wish to reverse, exactly the same as what you would use in {% url %} template tag.
  • args_or_kwargs (optional): An array of arguments, e.g. ['article', 4] or an object of keyword arguments, such as {'type': 'article', 'id': 4}.

Examples

A typical Angular Controller would use the service djangoUrl such as:

var myApp = angular.module('MyApp', ['ng.django.urls']);

myApp.controller('RemoteItemCtrl', ['$scope', '$http', 'djangoUrl', function($scope, $http, djangoUrl) {

    $scope.loadItem = function() {
        var fetchItemURL = djangoUrl.reverse('namespace:fetch-item');
        $http.get(fetchItemURL).success(function(item) {
            console.log('Fetched item: ' + item);
        }).error(function(msg) {
            console.error('Unable to fetch item. Reason: ' + msg);
        });
    }

}]);

and with args:

$http.get(djangoUrl.reverse('api:articles', [1]))

or with kwargs:

$http.get(djangoUrl.reverse('api:articles', {'id': 1}))