MelbyJim
MelbyJim

Reputation: 35

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="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

Answers (2)

Sebastian Wozny
Sebastian Wozny

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 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="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

AlvaroAV
AlvaroAV

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

Related Questions