I want to upload a file, process it in a Celery task, and show a progress bar using AJAX. but I did not get the solution. Can you help me with this task?
Views.py
# Create your views here.
def index(request):
if request.method == 'POST':
myfile =request.FILES['file']
fs = FileSystemStorage()
filename = fs.save(myfile.name , myfile)
uploaded_file_url = fs.url(filename)
data = process_file.delay(myfile.name)
task_id=data.task_id
return render(request , 'index.html', context={'task_id':task_id})
else:
return render(request , 'index.html')
task.py
def task_status(request, task_id):
if 'task' in request.GET:
task_id = request.GET['task_id']
else:
return HttpResponse('no job id given')
task = AsyncResult(task_id)
data = {
'state': task.state,
'result': task.result,
}
return HttpResponse(json.dumps(data), content_type='application/json')
# return render(request, 'progress.html', data)
Task.py
#shared_task(bind=True)
def process_file(self, file_name):
print('Uploading image...')
progress_recorder = ProgressRecorder(self)
result = 0
for i in range(5):
time.sleep(1)
result += i
instance = Tooltype(image=file_name)
instance.save()
#fs.delete(file_name)
print('Uploaded!')
progress_recorder.set_progress(i + 1, 5)
return result
index.html
<body>
<h1>select your file to process it!</h1>
<div class='progress-wrapper'>
<div id='progress-bar' class='progress-bar' style="background-color: #68a9ef; width: 0%;"> </div>
</div>
<div id="progress-bar-message">Waiting for progress to start...</div>
<form id="process-raw-data" action="" method="post" enctype="multipart/form-data">
{% csrf_token %}
<input type="file" id="file" name="file" >
<button type="submit" class="btn btn-success">Submit</button>
</form>
{% if task_id %}
<script>
var progressUrl = "{% url 'celery_progress:task_status' task_id %}";
function customResult(resultElement, result) {
$( resultElement ).append(
$('<p>').text('Sum of all seconds is ' + result)
);
}
$(function () {
CeleryProgressBar.initProgressBar(progressUrl, {
onResult: customResult,
})
});
</script>
{% endif %}
<script src="{% static 'celery_progress/celery_progress.js' %}"></script>
<script src="{% static 'assets/js/main.js' %}"></script>
</body>
when i upload a file and click on submit button it shows the progress bar but the file not shown in page and the task is successed and image is not uploading and show on page.
[2022-04-20 15:37:52,815: INFO/MainProcess] Task toolapp.tasks.process_file[b219aba3-d170-49e2-925c-3ad1c0a7c54b] succeeded in 5.327999999979511s: 10
thanks and got stuck on this task please help me.
Related
I try to upload two forms with one submit button.
A user can select a pdf file and a excel file. And then uploading both files. And then the contents of both are returned.
So I try to upload both files with one submit button.
But the two selected file options are not visible for uploading the files.
So I have the template like this:
{% extends 'base.html' %} {% load static %} {% block content %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Create a Profile</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link rel="stylesheet" type="text/css" href="{% static 'main/css/custom-style.css' %}" />
<link rel="stylesheet" type="text/css" href="{% static 'main/css/bootstrap.css' %}" />
</head>
<body>
<div class="container center">
<span class="form-inline" role="form">
<div class="inline-div">
<form class="form-inline" action="/controlepunt140" method="POST" enctype="multipart/form-data">
<div class="d-grid gap-3">
<div class="form-group">
{% csrf_token %}
{{ form.0.as_p }}
<button type="submit" name="form_pdf" class="btn btn-warning">Upload!</button>
</div>
<div class="form-outline">
<div class="form-group">
<textarea class="inline-txtarea form-control" id="content" cols="70" rows="25">
{{content}}</textarea>
</div>
</div>
</div>
<div class="d-grid gap-3">
<div class="form-group">
{{ form.1.as_p }}
</div>
<div class="form-outline">
<div class="form-group">
<textarea class="inline-txtarea form-control" id="content" cols="70" rows="25">
{{conten_excel}}</textarea>
</div>
</div>
</div>
</form>
</div>
</span>
</div>
</body>
</html>
{% endblock content %}
and the views.py:
class ReadingFile(View):
def get(self, *args, **kwargs):
return render(self.request, "main/controle_punt140.html", {
"form1": UploadFileForm(),
"form2": ExcelForm()
})
def post(self, *args, **kwargs):
filter_text = FilterText()
types_of_encoding = ["utf8", "cp1252"]
form1 = UploadFileForm(
self.request.POST, self.request.FILES, prefix="form1")
form2 = ExcelForm(self.request.FILES,
self.request.FILES, prefix="form2")
content = ''
content_excel = ''
if form1.is_valid() and form2.is_valid() and self.request.POST:
uploadfile = UploadFile(image=self.request.FILES["upload_file"])
excel_file = self.request.FILES["upload_file"]
uploadfile.save()
for encoding_type in types_of_encoding:
with open(os.path.join(settings.MEDIA_ROOT, f"{uploadfile.image}"), 'r', encoding=encoding_type) as f:
if uploadfile.image.path.endswith('.pdf'):
content = filter_text.show_extracted_data_from_file(
uploadfile.image.path)
else:
content = f.read()
if uploadfile.image.path.endswith('xlsx'):
wb = openpyxl.load_workbook(excel_file)
worksheet = wb['Sheet1']
print(worksheet)
excel_data = list()
for row in worksheet.iter_rows():
row_data = list()
for cell in row:
row_data.append(str(cell.value))
excel_data.append(row_data)
print(excel_data)
content_excel = excel_data
else:
content_excel = f.read()
return render(self.request, "main/controle_punt140.html", {
'form1': ExcelForm(),
'form2': UploadFileForm(),
"content": [content, content_excel]
})
# I've adjusted the indent here to what I think it should be.
return render(self.request, "main/controle_punt140.html", {
"form1": form1,
"form2": form2,
})
and forms.py:
class UploadFileForm(forms.Form):
upload_file = forms.FileField(required=False)
class ExcelForm(forms.Form):
upload_file = forms.FileField(required=False)
urls.py:
urlpatterns = [
path('', views.starting_page, name='starting_page'),
path('controlepunt140', views.ReadingFile.as_view(), name='controlepunt140'),
]
The variable name used in the template is the key of the dictionary, not the value. The value is what is inserted into the template when django renders the page.
You have {{form1.as__p}} in your template, but you send "form": [form1, form2] as your context, so the variable in the template should be {{ form.0.as_p }} and {{ form.1.as_p }}. I haven't tested this, but if it doesn't work, you could just send the two forms separately like:
from django.shortcuts import redirect
class ReadingFile(View):
def get(self, *args, **kwargs):
return render(self.request, "main/controle_punt140.html", {
"form1": UploadFileForm(),
"form2": ExcelForm()
})
def post(self, *args, **kwargs):
filter_text = FilterText()
types_of_encoding = ["utf8", "cp1252"]
form1 = UploadFileForm(self.request.POST, self.request.FILES, prefix="form1")
form2 = ExcelForm(self.request.FILES, self.request.FILES, prefix="form2")
content = ''
content_excel = ''
if form1.is_valid() and form2.is_valid() and self.request.POST:
uploadfile = UploadFile(image=self.request.FILES["upload_file"])
excel_file = self.request.FILES["upload_file"]
uploadfile.save()
for encoding_type in types_of_encoding:
with open(os.path.join(settings.MEDIA_ROOT, f"{uploadfile.image}"), 'r', encoding=encoding_type) as f:
if uploadfile.image.path.endswith('.pdf'):
content = filter_text.show_extracted_data_from_file(
uploadfile.image.path)
else:
content = f.read()
if uploadfile.image.path.endswith('xlsx'):
#Uploading excel form:
#this is just logic.
pass
else:
content_excel = f.read()
# You probably should do a redirect after the form is
# submitted, rather than render the page.
return redirect('main:controlepunt140')
# return render(self.request, "main/controle_punt140.html", {
'form1': ExcelForm(),
'form2': UploadFileForm(),
"content": [content, content_excel]
})
# I've adjusted the indent here to what I think it should be.
return render(self.request, "main/controle_punt140.html", {
"form1": form1,
"form2": form2,
})
You probable should also change to a redirect after the form is submitted and saved successfully. Check out Post/Redirect/Get and/or rendering content after a succesful post request.
Edit
Changed template to use {{ form.0.as_p }} as indicated by #nigel239
You can redirect to the same page where the form was submitted, so if the user hits the refresh button on their browser for some reason, you will not get an alert box asking the user to resend the form.
I'm having a three function in my django site views but I can only run one. I have never used celery, can you help me to transform this into the celery tasks?
As you can see, I want to save document which is uploaded by user, and then I want to do some pandas stuff with that file, and after that I want to show pandas stuff in html page.
This is forms.py
class DocumentForm(forms.Form):
docfile = forms.FileField(label='Select a file')
This is views.py
def save_exls(request):
if request.method == 'POST':
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile=request.FILES['docfile'])
newdoc.save()
return redirect('html_exls')
else:
form = DocumentForm()
documents = Document.objects.all()
context = {'documents': documents, 'form': form,}
return render(request, 'list.html', context)
def pandas_exls(request):
if request.method == "POST":
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
output = io.BytesIO()
newdoc = request.FILES['docfile']
dfs = pd.read_excel(newdoc, sheet_name=None, index_col=[0])
writer = pd.ExcelWriter(output)
for name, df in dfs.items():
#pandas stuff
done.to_excel(writer, sheet_name=name)
output.seek(0)
response = HttpResponse(
output, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
else:
form = DocumentForm()
return render(request, 'list.html', {'form': form})
def html_exls(request):
if request.method == "POST":
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
output = io.BytesIO()
newdoc = request.FILES['docfile']
dfs = pd.read_excel(newdoc, sheet_name=None, index_col=[0])
writer = pd.ExcelWriter(output)
for name, df in dfs.items():
#pandas stuff for html
done.to_excel(writer, sheet_name=name)
html = done.to_html()
print(html)
output.seek(0)
response = HttpResponse(
output, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
else:
form = DocumentForm()
return render(request, 'list.html', {'form': form})
This is html file, list.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Django site</title>
</head>
<body>
<!-- Upload form. Note enctype attribute! -->
<form action="{% url "pandas_exls" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload"/></p>
</form>
<br/>
{{html|safe}}
</body>
</html>
I use task_api for this, this is a django project that keeps track of the functions and provides some javascript to poll the backend for a change and updates when the functions are done running.
It does not yet seem to support file parameters, but you could save the file first, and then in javascript call the next method to operate on that file once saved, and display progress.
I would write 3 endpoints, 1 to upload the file, using the form, then 1 ajax endpoint you call in javascript to process the file, this will return when it is done, at which point you can redirect to the 3rd endpoint which will download the file.
e.g.
views.py
from task_api.tasks import Task
from task_api.params import IntParameter, StringParameter
class Pandas(Task):
name = 'pandas'
inputs = {
'documentid': IntParameter(),
}
outputs = {'output': StringParameter()}
def run(self, documentid):
self.progress = 0
output = io.BytesIO()
newdoc = Document.objects.get(id=documentid)
dfs = pd.read_excel(newdoc.docfile, sheet_name=None, index_col=[0])
writer = pd.ExcelWriter(output)
for name, df in dfs.items():
#pandas stuff
self.progress += 1 # update progress so we can show something to user in javascript
done.to_excel(writer, sheet_name=name)
output.seek(0)
Document.done = True
Document.output = output
Document.save()
return documentid
# configure /download in your urls.py to point to this view with documentid parameter
def download_exls(request, documentid):
response = HttpResponse(
Document.objects.get(id=documentid).output, content_type='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet')
response['Content-Disposition'] = 'attachment; filename=%s' % filename
return response
def save_exls(request):
if request.method == 'POST' and request.is_ajax():
form = DocumentForm(request.POST, request.FILES)
if form.is_valid():
newdoc = Document(docfile=request.FILES['docfile'])
newdoc.save()
return HttpResponse(json.dumps({'documentid': newdoc.id}), content_type="application/json")
else:
form = DocumentForm()
documents = Document.objects.all()
context = {'documents': documents, 'form': form,}
return render(request, 'list.html', context)
and in your list.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Django site</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="{% static 'django-task-api.min.js' %}"></script>
<script type="text/javascript">
function runtask(task, documentid, progressdivname) {
TaskAPI.run(task, documentid, function(json) {
if (json.target === null || json.progress === null) {
return false
}
document.getElementById(progressdivname).innerHTML = 'Progress: ' + json.progress + ' / ' + json.target
})
.then(function(json) {
# panda's is done, download doc
window.location = '/download/' + json.outputs.documentid;
})
return false
}
$(document).ready(function (e) {
$("#form").on('submit',(function(e) {
e.preventDefault();
$.ajax({
url: "/upload",
type: "POST",
data: new FormData(this),
contentType: false,
cache: false,
processData:false,
beforeSend : function()
{
//$("#preview").fadeOut();
$("#err").fadeOut();
},
success: function(documentid)
{
// process uploaded file.
runtask('pandas', {'documentid': documentid}, 'progress')
}
,
error: function(e)
{
$("#err").html(e).fadeIn();
}
});
}));
});
</script>
</head>
<body>
<!-- Upload form. Note enctype attribute! -->
<form action="{% url "pandas_exls" %}" method="post" enctype="multipart/form-data">
{% csrf_token %}
<p>{{ form.non_field_errors }}</p>
<p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>
<p>
{{ form.docfile.errors }}
{{ form.docfile }}
</p>
<p><input type="submit" value="Upload"/></p>
</form>
<br/>
<div id="progress"></div>
</body>
</html>
Be advised, this will allow anyone to download any file, just based on the id, you will probably want to add some authentication checks if this is not intended, you might also want to do some garbage collection and cleanup because this will keep all documents in your database.
I have
index.html
<p>input an image</p>
<p>
<form>
<input type="file" name="pic" accept="image/.jpg" onchange="loadFile(event)"></input>
<img id="output"/>
<script>
var loadFile = function(event) {
var output = document.getElementById('output');
output.src = URL.createObjectURL(event.target.files[0]);
};
</script>
</form>
</p>
<p>
<form>
<input type="submit" value="result"></input>
</form>
</p>
views.py
from django.shortcuts import render
def test(request):
if request.POST:
d = request.POST.dict()
img = d.get("pic")
a=image_array(img) # convert image to array use to test model
r=model(a) #
return render(request, "./index.html",r)
else:
return render(request, "./index.html")
how can I show the result of predict below the submit button?
I want to upload 2 images from requests. I am creating the function which accepts the request.files as a parameter and save both images.
The function is :
def store_offer_images(files, **service_response):
"""
Stores the Images
"""
create_diretory_if_not_exist()
lrg_img, sml_img = files.get('detail_image'), files.get('listing_image')
lrg_img_filename = service_response.get('content').get('offerId') + ".png"
sml_img_filename = service_response.get('content').get('offerId') + ".png"
sml_img.save(
os.path.join(config.NORMAL_FILE_UPLOAD_FOLDER, sml_img_filename))
lrg_img.save(
os.path.join(config.LARGE_FILE_UPLOAD_FOLDER, lrg_img_filename))
When I am trying to save the images. It saves properly. files is the request.files and service_response is the kwargs.
When I want to open image in Finder(OS GUI Window), then I got the message:
The file “b516f2dca72e4f559c3a72a1f48727a9.png” could not be opened because it is empty.
How can I upload the images?
Edit:
When I look files in the pdb, here are the response:
(pdb) files.get('detail_image')
(pdb) <FileStorage: u'python-640x444.png' ('image/png')>
The model which models my request data is:
import datetime
from app_config import AppConfig
class Offer(object):
"""
Offer Details
"""
def __init__(self, form):
self.REST_API_TIME_FORMAT = AppConfig().REST_API_TIME_FORMAT
self.title = form.get('title')
self.start_date = form.get('startsOn') + ' 00:00'
self.end_date = form.get('endsOn') + ' 23:59'
self.short_description = form.get('shortDescription')
self.long_description = form.get('longDescription')
self.outlets = form.getlist('outlets')
self.offer_value = form.get('offerValue')
self.offer_old_value = form.get('oldValue')
self.currency = form.get('currency')
def add_offer_body(self):
"""
Return the request body in json format
"""
outlets_list = []
for i in self.outlets:
outlets_list.append({'code': i})
starts_on_date = datetime.datetime.strptime(
self.start_date, '%d/%m/%Y %H:%M')
ends_on_date = datetime.datetime.strptime(
self.end_date, '%d/%m/%Y %H:%M')
body = {
"outlets": outlets_list,
"title": self.title,
"shortDescription": self.short_description,
"longDescription": self.long_description,
"endsOn": ends_on_date.strftime(self.REST_API_TIME_FORMAT),
"startsOn": starts_on_date.strftime(self.REST_API_TIME_FORMAT),
"isActive": "true",
}
if self.offer_value is not u'':
body['offerValue'] = {
"value": self.offer_value,
"currency": self.currency
}
if self.offer_old_value is not u'':
body["offerOldValue"] = {
"value": self.offer_old_value,
"currency": self.currency
}
return body
def __repr__(self):
return self.title
The views.py is:
#portal.route('/admin/offers/add', methods=['POST'])
def add_offer():
"""
Return status of added offer
"""
offer = Offer(request.form)
if controller.valid_content(request.files):
service_response = controller.add_offer(offer)
if 'errors' in service_response:
message = str(service_response.get('errors')[0].get('message'))
flash("Adding Offer Failed.!! " + message)
current_app.logger.error(
'Offer adding failed with details' + str(request.form))
return redirect(url_for('portal.list_running_offers'))
else:
controller.store_offer_images(request.files, **service_response)
current_app.logger.info('User added a offer successfully.')
flash("Offer added successfully..!!")
return redirect(url_for('portal.list_running_offers'))
else:
flash("Please upload all Images of mentioned Resolution.!!")
return render_template(
'addoffer.jinja', body=offer.add_offer_body(), help=help_messages)
The HTML is:
{% extends "base.jinja" %}
{% block script %}
<script type="text/javascript" src="static/js/addOffer.js"></script>
<script type="text/javascript" src="static/js/bootstrap-datepicker.min.js"></script>
<link href="static/css/datepicker.css" rel="stylesheet">
{% endblock %}
{% block title %}
Add Offer
{% endblock %}
{% block content %}
<legend><h1>
Add Offer
</h1></legend>
<br>
<div class="row">
<div class="col-md-1"></div>
<div class="col-md-10">
<form id="offerForm"enctype="multipart/form-data" class="form-horizontal" action="{{ url_for('portal.add_offer') }}" data-toggle="validator" role="form" method="post">
<div class="form-group">
<label class="control-label col-xs-3" for="file">OFFER LISTING IMAGE *</label>
<div class="col-xs-7 input-group">
<input id="image" type="file" class="form-control" name="listing_image" accept="image/x-png" data-error="{{help.listing_image}}" required>
<span class="help-block with-errors">{{help.listing_image}}</span>
</div>
</div>
<div class="form-group">
<label class="control-label col-xs-3" for="file">OFFER DETAIL IMAGE *</label>
<div class="col-xs-7 input-group">
<input id="image" type="file" class="form-control" name="detail_image" accept="image/x-png"
data-error="{{help.detail_image}}" required>
<span class="help-block with-errors">{{help.detail_image}}</span>
</div>
</div>
</form>
</div>
<div class="col-md-1"></div></div>
</div>
{% endblock %}
I fixed the problem. It was happening because If I perform any operation on Image, it will move my pointer at last, so when you save the image, it start saving image where your pointer is, which is at the last. So the saved image is empty.
Now to fixed this I just move my pointers to the beginning. Here is sample code what I did:
if img is not None and img.filename != u'':
img.seek(0, os.SEEK_END)
size = img.tell()
imgs = Image.open(img)
res = imgs.size
img.seek(0)
I am trying to implement "Upload Progress Bar" in Django.
Following is my code in the template file:
{% extends "index_base.html" %}
{% block content %}
<script src="/media/js/functions.js" type="text/javascript"></script>
<script src="/media/js/jquery.js" type="text/javascript"> </script>
<script type="text/javascript">
var xhrObject1;
var xhrObject2;
function createXMLHttpObject()
{
var xhrObject; // The variable that makes Ajax possible!
try
{
xhrObject = new XMLHttpRequest();
}
catch (e)
{
try{
xhrObject = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e){
try {
xhrObject = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {
xhrObject = null;
}
}
}
return xhrObject;
}
function ajaxFunction()
{
xhrObject1 = createXMLHttpObject();
if (xhrObject1 == null)
{
alert("Your browser does not support ajax.");
return;
}
xhrObject1.onreadystatechange = function(){
if(xhrObject1.readyState == 4){
document.getElementById("targetDiv").innerHTML = xhrObject1.responseText;
}
else
{
xhrObject2 = createXMLHttpObject();
xhrObject2.onreadystatechange = function(){
if(xhrObject2.readyState == 4){
document.getElementById("targetDiv").innerHTML = xhrObject2.responseText;
}
else
{
document.getElementById("targetDiv").innerHTML = "getting progress...";
}
}
xhrObject2.open("GET", "/upload_progress.psp", true);
xhrObject2.send(null);
}
}
var arrFiles = document.getElementById('id_file');
var fileToUpload = arrFiles.files[0];
xhrObject1.open("POST", "/upload.psp/", true);
xhrObject1.send(fileToUpload);
}
function submitForm()
{
document.forms["myform"].submit();
ajaxFunction();
return false;
}
</script>
<div id="main_container">
{% include "includes/nav.html" %}
<!------- Main Contents ---------->
<div id="contents_holder">
<div id="contents">
<div id="c_banner">
<span class="main_title">Upload File</span>
</div>
<div id="targetDiv" > </div>
<div id="setting">
<form name="myform" id="myform" action="/upload.psp/" method="post" enctype="multipart/form-data">
<h2>Upload File</h2></br>
<p>{{ form.file.label_tag }} {{ form.file }}</p></br>
<input type="button" value="Upload" name="uploadButton" onclick="javascript:return submitForm();"/>
<input type="button" value="Cancel" name="cancelUploadButton" onclick ="cancelUploadClicked()"/>
<input type="hidden" value="title" name="title" id="title" />
</form>
</div>
</div>
</div>
</div>
{% endblock %}
Following are my two functions inside views.py:
#condition(etag_func=None)
def upload(request):
if request.method == 'POST':
form = UploadFileForm(request.POST, request.FILES)
if form.is_valid():
#handle_uploaded_file(request.FILES['file'])
f = request.FILES['file']
filename = "/host_lighttpd/var/www/htdocs/satellite/static/Data/" + f.name
destination = open(filename, 'wb+')
for chunk in f.chunks():
destination.write(chunk)
#yield chunk
request.session['uploaded'] += chunk
destination.close()
return render_to_response('uploadsuccess.html')
else:
form = UploadFileForm()
return render_to_response('upload.html', {'form': form})
def upload_progress(request):
#uploaded = request.session['uploaded']
return HttpResponse("Upload progress function...")
#return HttpResponse(uploaded)
My problem is how can I return the upload status back to the
second ajax call (GET method), so that it can be eventually updated
inside the html.
I don't know how can I return the ongoing uploading status.
Any help would be appreciated. Thanks in advance.
I recently had to do a bit of digging to find a solution for this myself.
Check out :-
http://fairviewcomputing.com/blog/2008/10/21/ajax-upload-progress-bars-jquery-django-nginx/
I have not tried the solution referenced yet, but it looks reasonable enough.
It involves registering a custom file upload class to expose the upload progress information.