Wouldn't it be nice to call a Django view method, directly from your AngularJS controller, like a Remote Procedure Call or say Remote Method Invocation?
By nature, Single Page Web Applications implemented in Django, require one single View. These kind of applications can however not always be build around the four possible request methods GET
, PUT
, POST
and DELETE
. They rather require many different entry points to fulfill the communication between the client and the server.
Normally, this is done by adding a key to the request data, which upon evaluation calls the appropriate method. However, such an approach is cumbersome and error-prone.
Django-Angular offers some helper functions, which allow a client to call a View's method just as if they would be normal asynchronous functions. To achieve this, let your View's class additionally inherit from JSONResponseMixin:
from django.views.generic import View
from djangular.views.mixins import JSONResponseMixin, allow_remote_invocation
class MyJSONView(JSONResponseMixin, View):
# other view methods
@allow_remote_invocation
def process_something(self, in_data):
# process in_data
out_data = {
'foo': 'bar',
'success': True,
}
return out_data
In this View, methods decorated with @allow_remote_invocation
can now be invoked remotely, for instance in an AngularJS controller. To handle this in an ubiquitous manner, Django-Angular implements two special template_tag, which exports all the methods allowed for remote invocation to an AngularJS Provider.
The AngularJS Provider djangoRMIProvider
shall be configured during the initialization of the client side, such as:
{% load djangular_tags %}
…
<script type="text/javascript">
my_app.config(function(djangoRMIProvider) {
djangoRMIProvider.configure({% djng_all_rmi %});
});
</script>
This makes available all methods allowed for remote invocation, from all View classes of your Django project.
Alternatively, the AngularJS Provider djangoRMIProvider
can be configured during the initialization of the client side, such as:
my_app.config(function(djangoRMIProvider) {
djangoRMIProvider.configure({% djng_current_rmi %});
});
This makes available all methods allowed for remote invocation, from the current View classes of your Django project.
By injecting djangoRMI
, allowed methods from your Django Views can be called directly from any AngularJS Controller. This example shows how to call methods configured with the template tag djng_current_rmi
:
my_app.controller("SinglePageCtlr", function($scope, djangoRMI) {
$scope.invoke = function() {
var in_data = { some: data };
djangoRMI.process_something(in_data)
.success(function(out_data) {
// do something with out_data
});
};
});
If djangoRMIProvider
is configured using the template tag djng_all_rmi
, the allowed methods are grouped into objects named by their url_name. If these URL patterns are part of a namespace, the above objects furthermore are grouped into objects named by their namespace.
Note
djangoRMI is a simple wrapper around AngularJS's built in $httpProvider. However, it automatically determines the correct URL and embeds the method name into the special HTTP-header DjNg-Remote-Method
. In all other aspects, it behaves like $httpProvider.
Sometimes you only have to retrieve some data from the server. If you prefer to fetch this data using an ordinary GET request, ie. one without the special AngularJS provider djangoRMI
, then it is possible to hard-code the method for invocation in the urlpatterns inside the URL dispatcher.
class MyResponseView(JSONResponseMixin, View):
def get_some_data(self):
return {'foo': 'bar'}
def get_other_data(self):
return ['baz', 'cap']
urlpatterns = patterns('',
…
url(r'^fetch-some-data.json$', MyResponseView.as_view(), {'invoke_method': 'get_some_data'}),
url(r'^fetch-other-data.json$', MyResponseView.as_view(), {'invoke_method': 'get_other_data'}),
…
)
If a client calls the URL /fetch-some-data.json
, the responding view dispatches incoming requests directly onto the method get_some_data
. This kind of invocation only works for GET requests. Here the fetching methods do not require the decorator @allow_remote_invocation
, since the programmer determines all possible invocations.