MelbyJim MelbyJim - 4 years ago 145
Javascript Question

Django. The number won't increase after ajax call

I am rewriting this question, because I am uncertain if I would produce a duplicate if posting a new one. The first comments is answer to the original question.

I have a exam project which is partly to write a Django site with notes where a logged in user can vote on a note.

The html code, urls, view and jQuery don't give any errors. However, the number of likes will not increase after clicking the thumbs up icon from Bootstrap.

Updated with suggestions form Liαrεz and Sebastian Wozny

Can anyone please help me?

JS file

$(document).ready(function(){
var csrftoken = $.cookie('csrftoken');
$("#increase_num_likes_thumb").click(function(event){
event.preventDefault();
$.ajax({
method: "POST",
headers: { 'X-CSRFToken': $.cookie('csrftoken') },
url: $('#num_likes_url').val(),
success: function(data){
result = JSON.parse(data);
if (result.error){
consloe.log(result.error_text);
}else{
var num_likes_updated = result['num_likes_updated'];
$("#num_likes_div").html(num_likes_updated);
}
}
});
});


});

HTML

<div class="col-sm-10">
{% if notes%}
{% for note in notes %}
<div class="col-sm-5" style="border: 1px solid; margin: 10px;">
<h3 class="page-header"><a href="{% url 'notes:detailnote'%}?id={{note.id}}"> {{ note.label }} </a> </h3>
<div style="padding: 5px;">
{{ note.body }}
<p>
<div>
<a href="/notes/?id={{ note.id }}/increase_num_likes/" id="increase_num_likes_thumb">
<span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
</a>
</div>
<div id="num_likes_div">
{{ note.num_likes }}
</div>
</p>
<input type="hidden" id="num_likes_url" value="/notes/increase_num_likes/?id={{ note.id }}" >


</div>


urls.py

from django.conf.urls import patterns, url, include
from notes.views import increase_num_likes

urlpatterns = patterns('',
url(r'^(P<id>[\d\w]+)/increase_num_likes/$', increase_num_likes, name='increase_numlikes'),


,

View

from import json

def increase_num_likes(request):
id = request.GET.get('id', None)
if id is None:
note = get_object_or_404(Note, id=id)
data = {'error': True, 'error_text': 'Not ID supplied'}
else:
note = Note.objects.get(id=int(id))
note.num_likes += 1
note.save()
data = {'num_likes_updated': note.num_likes}
return HttpResponse(simplejson.dumps(data))

Answer Source

Your problem lies in url: $('#num_likes_url').val()

<input type="hidden" id="num_likes_url" value="/notes/?id={{ note.id }}/increase_num_likes/" >

so valueis "/notes/?id={{ note.id }}/increase_num_likes/" which is not a valid URI. From wikipedia:

<scheme name> : <hierarchical part> [ ? <query> ] [ # <fragment> ]

The correct way would be to call if you'd like to retrieve the id as a get argument.

"/notes/increase_num_likes/?id={{ note.id }}"

your urls.py

url(r'^increase_num_likes/$', increase_num_likes, name='increase_numlikes')

Alternatively you could make use of djangos url parsing:

urls.py

url(r'^(P<id>[\d\w]+)/increase_num_likes/$', increase_num_likes, name='increase_numlikes')

views.py

from import json

def increase_num_likes(request,id):
if id is None:
    note = get_object_or_404(Note, id=id)
    data = {'error': True, 'error_text': 'Not ID supplied'}
else:
    note = Note.objects.get(id=int(id))
    note.num_likes += 1
    note.save()
    data = {'num_likes_updated': note.num_likes}
return HttpResponse(simplejson.dumps(data))

html

<div class="col-sm-10">
    {% if notes%}
        {% for note in notes %}
            <div class="col-sm-5" style="border: 1px solid; margin: 10px;">
                <h3 class="page-header"><a href="{% url 'notes:detailnote'%}?id={{note.id}}"> {{ note.label }} </a> </h3>
                <div style="padding: 5px;"> 
                    {{ note.body }}
                    <p>
                        <div>
                            <a href="/notes/{{ note.id }}/increase_num_likes/" id="increase_num_likes_thumb">
                                <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
                            </a>
                        </div>
                        <div id="num_likes_div">
                            {{ note.num_likes }}
                        </div>
                    </p>
                    <input type="hidden" id="num_likes_url" value="/notes/{{ note.id }}/increase_num_likes/" >


                </div>

Furthermore it's important to set the correct headers:

The documentation suggests you are required to set the X-CSRFToken header when posting data with AJAX that is not a form which contains the {% csrftoken %} tag.

With jquery acquiring the token on the client is straightforward:

var csrftoken = $.cookie('csrftoken');

Set the right header on your ajax call:

$.ajax({
      method: "POST",
      headers: { 'X-CSRFToken': $.cookie('csrftoken') }
      url: $('#num_likes_url').val()
    })

I suspect your POST never reaches your view and is caught by CSRFProtectionMiddleware

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download