Valachio
Valachio

Reputation: 1135

Django - Pass a list item's id/pk to the view with jQuery ajax

Here is my code, shortened for brevity.

HTML Template

{% for question in questions %}
    <div class="upvote"></div>
{% endfor %}

# lots of code later...

<script>
    $(".upvote").click(function(){
        $.ajax({
            type: "POST",
            url: "{% url 'upvote_for_question' %}",
            data: {
                'question': question
            },
            }
        })
    })
</script>

My <div class="upvote"> element is an upvote button for a question (think Stack Overflow's upvote button). As the code shows, every question in question_list has an upvote button.

My question is, when the user presses an upvote button, how do I pass the associated question's pk/id to the view?

Upvotes: 1

Views: 2600

Answers (2)

Borut
Borut

Reputation: 3364

One way would be to define url for upvote:

url(r'^questions/(?P<question_id>\w+)/upvote', views.question_upvote, name='question_upvote')

Then use the reverse url functionality in the template and pass url in the data attribute like:

{% for question in questions %}
    <div class="upvote" 
         id="button-{{ question.pk}}" 
         data-href="{% url 'question_upvote' question.pk %}">{{ question.upvotes }}
    </div>
{% endfor %}

And modify your jQuery to get url from data-href attribute plus add CSRF token, otherwise POST will fail with status 403. Something like:

$(".upvote").click(function(){
    var postData = {csrfmiddlewaretoken: '{{ csrf_token }}'}
    $.ajax({
        type: "POST",
        url: $(this).attr("data-href"),
        data: postData,
        success: function(new_number_of_upvotes) {
            $(this).html(new_number_of_upvotes)
        }
    })
})

Updated view reflecting these changes would be something in the sense of:

def question_upvote(request, question_id):
    if request.is_ajax() and request.method == 'POST':
        question = get_object_or_404(Questions, pk=question_id)
        question.upvotes += 1
        question.save()
        return HttpResponse(question.upvotes)
    else:
        return HttpResponseRedirect('/')

I haven't tested this, but I guess it should work.

Upvotes: 4

VMatić
VMatić

Reputation: 996

You could first give each div a unique id:

{% for question in questions %}
    <div class="upvote" id="button-{{ question.pk}}"></div>
{% endfor %}

Then pass that in the post data:

data: {
    'question': $(this).attr('id')
},

Upvotes: 2

Related Questions