Login

Django and jQuery -- pulling info from a long-running process

Author:
Donn
Posted:
August 21, 2008
Language:
Python
Version:
.96
Score:
2 (after 2 ratings)

Another sample of how to integrate Django and jQuery.

This starts a function in views.py that takes a long time to finish. It sets a session variable so that another function can report on the situation. We use jquery and ajax to 'pull' that data from Django so as to provide a progress report.

I don't yet know how to background a long-running process, but this is an okay stop-gap method to use. I hope.

d

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
urls.py
===
# The main url to kick it all off:
(r'^massupdate/$','scents.massupdate.views.drawMassUpdatePage'),
# Called by Ajax:
url(r'^doit/$','scents.massupdate.views.doit',name="doit"),
# Called by Ajax to pull status:
url(r'^getCount/$','scents.massupdate.views.getCount',name="getcount"),
	

views.py
===
from django.http import HttpResponse
from django.shortcuts import render_to_response
from django.utils import simplejson

import time

def drawMassUpdatePage( request ):
	request.session['count'] = 0
	request.session['done'] = False
	request.session.modified = True # May not need this.
	return render_to_response("massupdate/testajax.html") # template at end

# Kicks off the update. After this starts jquery will call
# getCount periodically to 'pull' results.
def doit( request ):
	# Do something long and slow
	for i in range(0,5000):
		request.session['count'] = i
		request.session.save() # Had to do this to actually use the session in getCount.
		#time.sleep(2) # Can make it even slower with this.

	request.session['done'] = True
	
	# This one is talking to a different func in the js.
	return HttpResponse('All done.',mimetype='text/plain')

# This one is being pulled by $.ajax in the js.
def getCount( request ):
	i =  request.session.get('count', 0 ) # Fetch the count or 0
	isitdone = request.session.get('done', False) # Fetch the status or False
	if isitdone:
		# It's all finished, so send a flag.
		d= {"done":True}
		j = simplejson.dumps(d)
		return HttpResponse( j, mimetype='application/javascript' )
	else:
		# It's busy, so send a flag and a count
		d= {"done":False,"count":i}
		j = simplejson.dumps(d)
		return HttpResponse( j, mimetype='application/javascript' )
	
template: testajax.html
===
<html>
<head>
	<script type="text/javascript" src="/media/js/jquery/jquery-1.2.6.pack.js"></script>
</head>
<body>

<script type="text/javascript">
$(document).ready(function() { 

		// The func that calls getCount
		function pull() {
		// I use $.ajax. getJSON seems to cache the last data on ie6. Firefox work tho.
		$.ajax ({
			type: "GET",
			url: "{% url getcount %}",
			dataType: "json",
			cache: false, //VITAL line: the getJON func does not prevent caching!
			success: updater //Call this func when we have some data
		})
		}

		// Func to use the data fetched
		function updater( data, success ) {
			if (data) {
				// If done flag sent, say so.
				if (data.done) {
					txt = "DONE";
				} else { 
					// We are busy, get the count and...
					txt = data.count;
					// set this to start again in 2 seconds:
					window.setTimeout( pull, 2000 );
				}
				// Display out count/message
				$('#msg').text( "SETTING TO:" + txt );
			}
		} //end updater

		// You can start it automagically like this:
		//$('#muffin').load("{% url doit %}");
		
		//Or with an anchor
		$("#go").click(function() {
				$(this).hide(); // Hide the anchor
				// Call doit func in Django view
				$('#muffin').load("{% url doit%}");
				// Start the pull function in 1 second:
				window.setTimeout( pull, 1000);
			});
	}); //end ready
</script>

<a id="go" href="#">Start</a>
<div id="muffin">DARN</div>
<div id="msg" style="border:1px solid red;">NUMBER</div>

</body>
</html>

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 3 months, 1 week ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 3 months, 2 weeks ago
  3. Serializer factory with Django Rest Framework by julio 10 months, 1 week ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 11 months ago
  5. Help text hyperlinks by sa2812 11 months, 3 weeks ago

Comments

sebastien-briois (on March 12, 2009):

Hi,

Thank you for this code.

I just can't make it work though. I've done everything you explained but Ajax requests keeps returning 'data.count = 0' ('doit' view has not stopped). It seems like request.session is not saved afterall, is it ? I'm using Apache and no cache system set.

Any idea?

Regards, Sébastien

#

Lancelot (on May 26, 2010):

This code won't respond to a browser while its progress. A user need to wait until the following loop will be end: for i in range(0,5000):

So obviously, a user knows when it's done, but never know the progress.

We need to move this loop into a threading.

#

Please login first before commenting.