Reputation: 35
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="row">
<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>
</div>
{% endfor %}
{% endif %}
</div>
</div>
urls.py
from django.conf.urls import patterns
from django.conf.urls import url
from django.conf.urls import 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'),
,
Views.py
import json
from django.http import HttpResponse
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))
Upvotes: 2
Views: 113
Reputation: 17506
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 value
is "/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="row">
<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>
</div>
{% endfor %}
{% endif %}
</div>
</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
Upvotes: 1
Reputation: 10563
You should change your AJAX view to:
from django.http import HttpResponse
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))
and change your AJAX .done to .success managing the error:
$(document).ready(function(){
$("#increase_num_likes_thumb").click(function(event){
event.preventDefault();
$.ajax({
method: "POST",
url: $('#num_likes_url').val()
})
.success: function(data) {
result = JSON.parse(data); # Parse the data received
if (result.error){
console.log(result.error_text);
}else{
var num_likes_updated = result['num_likes_updated'];
$("#num_likes_div").html(num_likes_updated);
}
})
});
});
Upvotes: 1