markwalker_ markwalker_ - 1 month ago 5
Python Question

How can I run a Django function on a button press which doesn't render content?

I'm getting on quite well with Django & Python, just got a search function working. But I'm unsure of my next problem.

I've got a function that connects to Amazon S3 and stores keys in my database. I currently run this when a page renders, but what I want is to have a button which runs this call so it'll be like a refresh button to update the database with the latest content.

The action on search goes to

/search/
so urls takes care of giving that a template and a view to run the search code. But if my update form has action="." and should change the page, how do you point it to the function? (I'm using generic views)

It'd probably be a good idea to render results from the function to the screen, but I first just want to understand how you call a function that doesn't necessarily show the user anything.

My function is fairly simple (and yes, I've added that first if statement as I try to implement this):

def updateRevFromS3(request):
if ('r' in request.POST) and request.POST['r'].stript():
s3 = boto.connect_s3(
settings.AWS_ACCESS_KEY_ID,
settings.AWS_SECRET_ACCESS_KEY) # Connect to Amazon S3
b = s3.get_bucket(
settings.AWS_STORAGE_BUCKET_NAME) # Find existing bucket to store data
revision = b.list(prefix="{{ update_revision }}")

for key in revision:
# download values to db
try:
obj = screenshots.objects.get(imgUrl=key.name,
mod_date=key.last_modified)
except screenshots.DoesNotExist:
obj = screenshots(imgUrl=key.name,
meta=key.metadata,
mod_date=key.last_modified)
obj.save()
print "Saving: " + key.name
else:
print key.name + " already exists."


And my form:

<form action="." method="get" id="updateForm">{% csrf_token %}
<label>Update images for revision:</label><br/>
<input type="text" name="r" value="{{ update_revision|escape }}"/>
<input type="submit" value="Update" />
</form>


The next step would be to give the user some feedback as a result, but I'll get on to that after I can call the function! Thanks :)

update

I've put some jQ in to catch the update form (I put an alert in to test this);

<script type="text/javascript">
$("#updateForm").bind("submit", function () {
$.post(ajax_url, {r: $(this).find('[name="r"]').val()}, function (data) {
// nothing here for now, but this is where you could update the UI, etc.
});
return false;
});
</script>


And my default view is as follows (this always falls through the final return);

def index(request):
if request.is_ajax():
print "is ajax"
return updateRevFromS3(request)
elif request.POST.get('r') == "updateForm":
print "is post"
return updateRevFromS3(request)
print "not ajax or post"
return render_to_response("base.html", RequestContext(request))


Seen as though I've not idea what I'm really doing with this, I'm not sure why my console window shows GET and POST requests on each page load. If thats the case why doesn't the index view return
updateRevFromS3()
?

Answer

If you use a normal form POST, the page will reload - that's just how HTTP works. To have a 'background' POST, you need to use AJAX. If you have jQuery on your page, you'll want to add an ID to your form so it can be easily selected, then do something like this:

$("#formid").bind("submit", function(){
    $.post(ajax_url, {r: $(this).find('[name="r"]').val()}, function(data){
        // nothing here for now, but this is where you could update the UI, etc.
    });
    return false;
});

Here are the relevant jQuery docs.

In your view, you can conditionally dispatch to the refreshing function based on request.is_ajax() (or any other condition, say, whether a particular POST key provided by a hidden input is present):

def your_view(request):
    if request.is_ajax(): return updateRevFromS3(request)
    elif request.POST.get("my-hidden-input-name") == "this-is-the-update-form":
        return updateRevFromS3(request)
    return normal_processing()