0

I tried to research but couldn't find a way to handle META requests in Django with Ajax. Refreshing a page everytime kind of destroys the UX. So if the code is something like this:

template

<a href="/like/?id={{ car.id }}" ># of likes: {{ car.likes }}</a>

views.py

def like_page(request):
    if 'id' in request.GET:
        id = request.GET['id']
        car = Cars.objects.get(id=id)
        car.likes += 1
        car.save()
    if 'HTTP_REFERER' in request.META:
        return HttpResponseRedirect(request.META['HTTP_REFERER'])
    return HttpResponseRedirect('/')

So the template sends the id of the object, and in the views it increments the like by 1. everytime this happens. Now the problem is that without Ajax it reloads the page everytime it happens. I am a backend developer, so I have almost no experience with jQuery and Ajax, so I have no clue how to approach this problem.

Any help would be appreciated. Thanks :)

miki725
  • 27,207
  • 17
  • 105
  • 121
Jonathan
  • 2,728
  • 10
  • 43
  • 73

1 Answers1

1

The way to do this is do apply progressive development - make non-js work, and then on top of that make enhancements using ajax or whatever other client technologies you want.

Django request has is_ajax (docs) method which is very useful for progressive development. The idea is that when the request is non-ajax, do whatever you did before, however if it is ajax, return the like counter so that js can update the page:

def like_page(request):
    if 'id' in request.GET:
        id = request.GET['id']
        car = Cars.objects.get(id=id)
        car.likes += 1
        car.save()

    if not request.is_ajax():
        if 'HTTP_REFERER' in request.META:
            return HttpResponseRedirect(request.META['HTTP_REFERER'])
        else:
            return HttpResponseRedirect('/')
    else:
        data = {
            'likes': car.likes
        }
        json_data = json.dumps(data)
        return HttpResponse(json_data, content_type='application/json')

Please note that this returns json data back. This is very useful because it is easily extensible in the future in case you have to return additional information.

Now for the js/jquery stuff:

Template

<a id="car_like" href="/like/?id={{ car.id }}" >
    # of likes: 
    <span id="car_like_count">{{ car.likes }}</a>
</a>

JS

$(document).ready(function () {
    $('#car_like').click(function(event) {
        event.preventDefault();
        var car_like = $(this),
            url = car_like.attr('href');
        $.getJSON(url, function(data) {
            $('#car_like_count', car_like).html(data.likes);
        });
        return false;
    });
});

This will overwrite the default behavior of the like anchor, and will send ajax request. Ajax request will return a new like counter for the car, which js will display in place of the old number. However if for some reason js is not supported, the default action will happen and the like anchor will still work.

Jonathan
  • 2,728
  • 10
  • 43
  • 73
miki725
  • 27,207
  • 17
  • 105
  • 121
  • Thank you so much! :) This worked just fine. Would This approach even work for submitting comments and adding the new submitted comments? – Jonathan Oct 15 '12 at 09:28
  • @Jonathan it would work as long as you are not subimitting `POST` requests; for those you need to enable [csrf protection](https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax) – Burhan Khalid Oct 15 '12 at 09:35
  • To simplify, for ajax requests to work, just add this js script before you send any requests. It is straight from Django docs, just everything is combined into a single file: https://gist.github.com/3892061 – miki725 Oct 15 '12 at 11:46
  • @miki725 your jQuery CSRF fix works just fine except for file uploads. My fileuploads dont seem to work with this approach. would you happen to know the reason for that? – Jonathan Jan 11 '13 at 09:36
  • @Jonathan When uploading files, you have to submit HTML form. You can't just manually request JSON response. You can use plugin like this (http://jquery.malsup.com/form/) to submit form via ajax. For this your view can be similar to what I described in an answer. If you however need to upload multiple files, you can use plugin like this (http://blueimp.github.com/jQuery-File-Upload/) which will upload many files via ajax. For this you will however need to create separate views to handle uploads. I did a demo a while back integrating above plugin with Django: https://vimeo.com/27230827 – miki725 Jan 12 '13 at 20:21
  • @miki725 please have a look at [this question](http://stackoverflow.com/questions/14300858/ajax-form-submission-files-not-getting-submitted) This might explain better how I am trying to implement ajax form submission – Jonathan Jan 13 '13 at 05:08
  • @Jonathan Responded in the question. Hopefully answer will provide more details. – miki725 Jan 13 '13 at 08:23