It took me a while to get Ajax calls working with Angular and Django REST. This is what finally got it done.

NOTE: The implementation below is not really REST. It is more intended to illustrate some workarounds and custom methods. If the client can adhere to REST, a lot of the code below won’t be needed. See the Django REST tutorial for a simpler implementation.

First, both frameworks use templates and they both use the same default syntax {{ }}. There are a couple ways to make them both play together. The easiest way is to surround Angular code with Django’s {% verbatim %} tags.

{% verbatim %}
        <tr ng-repeat="dbconn in dbconns">
            <td>{{ dbconn.name }}</td>
            <td>{{ dbconn.schemaname }}</td>
            <td>{{ dbconn.hostname }}</td>
            <td>{{ dbconn.port }}</td>
            <td>{{ dbconn.username }}</td>
            <td><button ng-click="remove()">DELETE</button></td>
        </tr>
    </table>
{% endverbatim %}

When defining your Angular app, there are some necessary configurations to use. I’ll let the comments do the explaining.

var app = angular.module('myappname', ['ngCookies']).
    config([
    '$httpProvider',
    function($httpProvider) {
        // Change content type for POST so Django gets correct request object
        $httpProvider.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';
        // 2 reasons: Allows request.is_ajax() method to work in Django
        // Also, so 500 errors are returned in responses (for debugging)
        $httpProvider.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
    }]).
    run([
    '$http',
    '$cookies',
    function($http, $cookies) {
        // Handles the CSRF token for POST
        $http.defaults.headers.post['X-CSRFToken'] = $cookies.csrftoken;
    }]);

The bottom line in the code above has a dependency on the angular-cookies.js file (in Angular’s standard bundle). So don’t forget to load that script before you load your Angular app.

<script src="{% static "myappname/js/angular-cookies.js" %}"></script>

JSON Data Exchange Example

Here is an example Ajax call method on the Angular Controller.

app.controller('MyAppController', function ($scope, $http){

    /* Post example */
    $scope.add = function(formdata) {
        // Add requesttype to data object
        formdata['requesttype'] = 'ADD';
        $http(
            {method: 'POST',
            url: '',
            data: $.param(formdata)
        }).
        success(function(data, status, headers, config) {
            // this callback will be called asynchronously
            // when the response is available
            $scope.dbconns = data['current_conns'];
        }).
        error(function(data, status, headers, config) {
            // called asynchronously if an error occurs
            // or server returns response with an error status.
            alert("Status: " + status + ", Data: " + data);
        });
    };
});
NOTE: There is a jQuery dependency to use $.param()

views.py

The code below shows an example of using a custom ['requesttype'] property to handle different types of Ajax calls in the same function.

from django.shortcuts import render
from django.http import HttpResponse
from managedb.models import DatabaseConnection
from managedb.serializers import DatabaseConnectionSerializer
from rest_framework.renderers import JSONRenderer

def example_page(request):
    # Draw initial page
    if request.method == 'GET':
        return render(request, 'homepage.html', {})

    # Handle posts
    elif request.method == 'POST':

        # Make sure request is Ajax
        if request.is_ajax():

            # Handle DELETE requests
            if request.POST['requesttype'] == 'DELETE':

                # Retrieve and then delete object by id
                current_conn = DatabaseConnection.objects.get(id=request.POST['id'])
                current_conn.delete()

                # Get updated list of connections
                context = {}
                # Use custom ModelSerializer to get data from QuerySet
                context['current_conns'] = DatabaseConnectionSerializer(DatabaseConnection.objects.all()).data

                # Return response as JSON
                return HttpResponse(JSONRenderer().render(context), content_type='application/json')

            # Handle ADD requests
            elif request.POST['requesttype'] == 'ADD':
                # TODO - Do stuff here
                pass

            else:
                # TODO - Handle wrong request types here
                pass


    else:
        # TODO - Handle wrong request types here
        pass

    return HttpResponse('error')

serializers.py

And then just to show the Class definition of the serializer used above.

from rest_framework import serializers
from managedb.models import DatabaseConnection

class DatabaseConnectionSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = DatabaseConnection

        # Optional to include certain fields
        # Here we are not returning the password field so it should never be exposed
        fields = ('id', 'name', 'hostname', 'port', 'username', 'schemaname')

Troubleshooting – Force CSRF Cookie

A final note on CSRF Cookies when going live. When I first pushed the project live I encountered an issue where the cookie was not being sent and ended up throwing 403 Forbidden errors on my Ajax calls. I didn’t investigate the issue too much, but the solution I found was to add the @ensure_csrf_cookie decorator to the main view function serving the core Django template.


from django.views.decorators.csrf import ensure_csrf_cookie

@ensure_csrf_cookie
def runcustomquery(request):
    # view function body...

Django has some very useful error pages built in that can help with a lot of debugging. Unfortunately sometimes you need to dig into the code a little more at run time to track down errors, etc.

Here are some additional methods for debugging Django…

Using pdb

pdb is part of the Python standard library. It allows you to set breakpoints, inspect objects, etc.

In Django, start your local server by invoking pdb

python -m pdb manage.py runserver

In your code, add this line right before the line you want to set a breakpoint on

import pdb; pdb.set_trace()

At the breakpoint, you will see the command line terminal stop and a (Pdb) prompt will show up. From here you can enter an object’s name to inspect it. You can also run simple functions to see what they output.

For example:

(Pdb) request.is_ajax()
True

Just type c to continue on from a breakpoint.

This doc is a work in progress…

Using Django version: 1.6.2

Basic Ajax Example

views.py

from django.shortcuts import render
def basicajax(request):
    context = {}

    # Draw initial page
    if request.method == 'GET':
        return render(request, 'basic_ajax.html', context)

    # Handle posts
    elif request.method == 'POST':

        # Make sure request is Ajax
        if request.is_ajax():
            context['textbox_data'] = request.POST['textbox']
            context['hiddenfield_data'] = request.POST['hiddenfield']

            # Return response as JSON
            return HttpResponse(json.dumps(context), content_type='application/json')
    else:
        # Handle errors here
        pass
Notes

  • We are returning an HttpResponse, not a render
  • content_type='application/json' is necessary. Otherwise the Ajax success callback returns the data as a string
  • content_type used to be mimetype. Some documentation online still shows up using this but it is now deprecated. Use content_type
  • The data that is passed in from the hidden fields can be used to separate different Ajax requests from the same page. Just give each Ajax form an identifier in a hidden field and use that field to handle the logic in views.py

basic_ajax.html

<html>
<head>
    <title>Basic Ajax Example</title>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
</head>
<body>
    <form id="form_id1">
        <input type="text" name="textbox">
        <input type="submit" value="Search">
        <input type="hidden" name="hiddenfield" value="Cant see me">
        {% csrf_token %}
    </form>
    Textbox value: <span id="textbox_val"></span>, Hidden field value: <span id="hiddenfield_val"></span>
</body>
<script>
$(document).ready(function() {
    $("#form_id1").submit(function(event){
        // Disable submit button
        $("#form_id1").find('input[type=submit]').prop("disabled",true);

        $.ajax({
            type:"POST",
            url:"",
            data: $("#form_id1").serializeArray(), // Easy way to capture all data from form
            success: function(data) {

                // Fill in our output spans
                $("span#textbox_val").html(data['textbox_data']);
                $("span#hiddenfield_val").html(data['hiddenfield_data']);

                // Enable submit button
                $("#form_id1").find('input[type=submit]').prop("disabled",false);
            },
            error: function(xhr, textStatus, errorThrown) {
                alert("Please report this error: "+errorThrown+xhr.status+xhr.responseText);
            }
        });
        return false; //<---- so page doesn't reload
    });
});</script>
</html>
Notes

  • Imports jQuery at the top
  • url="", within the Ajax call to submit to same page
  • To fill the data in the Ajax call use serializeArray(), not serialize()
  • {% csrf_token %} must be present within each form

urls.py

from django.conf.urls import patterns, include, url
from hellodjango.views import *
urlpatterns = patterns('',
    url(r'^examples/basicajax/', basicajax),
)

Recently I was fooling around with Chrome Extension development, mostly just to satisfy my curiosity about how it worked.

This article will show a basic template that illustrates one method of communication between two core components of a Chrome Extension. I don’t expect to be doing much more Extension development, but you never know, this might be useful in the future (or if some poor soul ends up reading this article).

TIP: This is just one method of communication. There are more, and some others might be better for your particular needs.

 

The basic idea of this Extension is to create a ticker that starts as soon as the extension is loaded (generally on browser load). The ticker increments every 5 seconds on its own. The user can click the Extension’s icon, loading a small extension popup that shows the same ticker amount and stays in sync with the icon’s ticker. It also has a button to manually increase the ticker by 10 ticks. Completely useless (I think?), but it hopefully illustrates a couple basic Chrome Extension concepts.

NOTE: This Extension uses Manifest Version 2. This is the most recent version at the time of publishing. More info on version differences.

 

Background page

Every extension has an invisible background page (maybe it’s optional). The background page is loaded as soon as the Extension is loaded into Chrome (generally when the browser first starts). This example uses both HTML and JavaScript files for the background page, but you can just use a JavaScript file.

NOTE: If you only want JavaScript for the background page (no HTML), the manifest.json file changes a bit. See documentation.

 

background.html

All our background.html file does is load our JavaScript file. I mainly included it here because it contains some DOM elements, allowing us to initialize some of our JavaScript code after the DOM is loaded.

<!doctype html>
<html>
  <head>
    <script src="background.js"></script>
  </head>
  <body>
  </body>
</html>

 

background.js

The background JavaScript is the one that creates and controls our ticker. The code is hopefully straightforward and well commented.

One thing to note is the listener that is started. More types of requests can easily be added by adding another case. Incoming requests can have arbitrary data attached to the request object (ie, request.data is used in one of the cases).


var masterTicker = {
	tickerInterval : 1000 * 5, // seconds
	ticker : 0,
	incrementTicker: function() {
		masterTicker.ticker++;
		masterTicker.updateTicker();
	},
	addToTicker: function(amount) {
		masterTicker.ticker += amount;
		masterTicker.updateTicker();
	},
	updateTicker: function() {
		if (masterTicker.ticker==0) {
			chrome.browserAction.setBadgeText({text: ""});
		} else {
			chrome.browserAction.setBadgeText({text: "" + masterTicker.ticker});
		}
		// Send ticker amount to popup page
		chrome.extension.sendRequest({method: 'updateTicker', data: masterTicker.ticker}, function(response) {
		});
	},
};

// Start our listener
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
	switch (request.method) 
	{
	case 'addToMasterTicker':
		masterTicker.addToTicker(request.data);
		sendResponse({result: 'success'});
		break;
	case 'getMasterTicker':
		sendResponse({result: '' + masterTicker.ticker});
		break;
	}
});

// Run our script as soon as the document's DOM is ready.
document.addEventListener('DOMContentLoaded', function () {
	// Start the interval for updating the ticker
	setInterval(function(){masterTicker.incrementTicker()},masterTicker.tickerInterval);
});

Also note the masterTicker.updateTicker function. This contains the syntax for sending a request to the popup.js. When we get to popup.js, you’ll see a corresponding listener that handles that type of request.

 

Popup page

popup.html

This file is also very simple.

<!doctype html>
<html>
  <head>
    <title>Basic Popup</title>
    <!-- JavaScript and HTML must be in separate files. -->
	<script src="popup.js"></script>
	
	<!-- Local copy of javascript is needed -->
	<script src="jquery-2.1.0.min.js"></script>
  </head>
  <body>
		<div>Current Ticker: <span id="ticker-amount"></span></div>
		<button id="add-ten-to-ticker">Add 10</button>
  </body>
</html>

 

popup.js

The popup.js version of the ticker stores a local copy of it’s own ticker but the initial value is grabbed from background.js (on page load). After that it should always be getting the latest ticker value from background.js.

Notice the similar methods of logging a listener that handles certain request.method values and also using chrome.extension.sendRequest to initiate it’s own communication.

var localTicker = {
	currentTicker : 0,
	getTicker: function() {
		// Get official ticker amount from background page
		chrome.extension.sendRequest({method: 'getMasterTicker'}, function(response) {
			// Store ticker amount
			localTicker.currentTicker = response.result;
			// Update the DOM with the result
			localTicker.updateTicker();
		});
	},
	addToTicker: function(amount) {
		// Request X amount to be added to ticker
		chrome.extension.sendRequest({method: 'addToMasterTicker', data:amount}, function(response) {
			// Get new official ticker amount
			localTicker.getTicker();
		});
	},
	updateTicker: function() {
		// Update the DOM to show the ticker value
		$( "#ticker-amount" ).text("" + localTicker.currentTicker);
	},
};

// Add listener to receive messages from background page
chrome.extension.onRequest.addListener(function(request, sender, sendResponse) {
	switch (request.method) 
	{
	case 'updateTicker':
		localTicker.currentTicker = request.data;
		localTicker.updateTicker();
		sendResponse({result: 'success'});
		break;
	}
});

// Run our script as soon as the document's DOM is ready.
document.addEventListener('DOMContentLoaded', function () {
	// Grab current ticker amount from background
	localTicker.getTicker();
	
	// Attach onclick event to button
	$("#add-ten-to-ticker").click( function() {
		localTicker.addToTicker(10);
	});
});

That’s really the meat and potatoes of showing this method of communication between background.js and popup.js.

 

The rest of the Extension

I’ll briefly go through the remaining parts of the extension and how to get it up and running.

 

manifest.json

Every Chrome Extension needs a manifest.json file. Here is what our’s looks like.

{
  "manifest_version": 2,

  "name": "Basic Ticker Extension",
  "description": "Demonstrates basic communication between background.js and popup.js",
  "version": "1.0",

  "browser_action": {
    "default_icon": "icon.png",
    "default_popup": "popup.html"
  },
  "background" : {"page": "background.html"}
}

 

Other files

You need 2 more files:

  • icon.png: A 19 x 19 image file
  • Local version of any JavaScript files you need (ie, jQuery)
Full file list

File list for extension

 

Loading and testing Extension

Getting the Extension working in your browser is very easy.

  1. Go to your Extensions console (via upper right button or chrome://extensions/ in your address box.
  2. Make sure Developer mode is turned on.
  3. Click Load unpacked extension… near the top of the page.
  4. Select the folder on your hard drive containing all of the Extension files

Now you should see the icon of your Extension in the upper right and a new entry in the Extensions list.

NOTE: To debug your background page, use the Inspect views: background.html link.

Just trying out some different methods of doing code display and syntax highlighting with a short snippet of basic Python module code.

 

Basic <code> tag

def main():
    pass

if __name__ == '__main__':
    main()

Well that’s pretty ugly, and I have to use “&nbsp;” to do indenting (pretty important for Python).

 

Wrap with a <pre> tag

A simple improvement is to wrap the <code> tags in <pre> tags. This will preserve formatting (tabs, spaces, newlines, etc.)

def main():
    pass

if __name__ == '__main__':
    main()

That looks much better. I can even copy from the webpage and paste into PyScripter and all the formatting characters come with it.

TIP: Add this line to your CSS to ensure that the code is using a monospace type (for consistent indenting). Most browsers do this by default, but you can force it to make sure.

pre { font-family: monospace; }

 

Google Code’s Prettify

Now, let’s try some syntax highlighting. Google Code’s Prettify is used on Google Code and StackOverflow for their highlighting. It has some nice features (ie, autorecognizes most major languages, also can specify the language, optional line numbering).

Since this is WordPress, “there’s a plugin for that”! The one used below is called “Prettify Code Syntax” by Jesús Carrera.
Just add the “prettyprint” class to the pre tag. Optionally you can add a language specifier class to the code tag as well.

def main():
    pass

if __name__ == '__main__':
    main()

Simple and looks great!

For line numbering, also add the “linenums” class to the <pre>

def main():
    pass

if __name__ == '__main__':
    main()