Search code examples
djangoajaxdjango-csrf

Django -- Forbidden (CSRF token missing or incorrect.): /vote/


I have a website with an AJAX upvote or downvote option on a post. The problem I am having is that the voting works on my Post detail page but not on my index page. I am getting the error Forbidden (CSRF token missing or incorrect.): /vote/

Both pages call the same view and URL pattern.

index.html:

{% for post in posts %}
    <span id="post_{{forloop.counter}}" data-value="{{post.id}}"></span>
    <button class="vote_action" value="upvote_button"> + </i></button>
    
    <span id="votes">{{post.points}}</span>
                                  
    <button class="vote_action" value="downvote_button"> - </button>
{% endfor %}

<script type="text/javascript">
 // JQUERY - AJAX SCRIPT FOR voting
 $(document).ready(function(){
   {% for post in posts %}
   $('.vote_action').click(function(e) {
      var postid = document.getElementById('post_{{forloop.counter}}').getAttribute('data-value');
          var button = $(this).attr("value");
          e.preventDefault();
          $.ajax({
            type: 'POST',
            url: '{% url "vote" %}',
            data: {
              postid: postid,
              csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
              action: 'postvote',
              button: button,
            },
            success: function(json){
              if (json.length < 1 || json == undefined) {
                //empty
              }
              document.getElementById("votes").innerHTML = json['result']
            },
            error: function(xhr, errmsg, err) {}
          })
        })
        {% endfor %}
      })
      </script>

post_detail.html:

    <span id="vote_id" data-value="{{post.id}}"></span>
    <button class="vote_action" value="upvote_button"> + </i></button>
    <span id="votes">{{post.points}}</span>                           
    <button class="vote_action" value="downvote_button"> - </button>

    <script type="text/javascript">
       // JQUERY - AJAX SCRIPT FOR voting
       $(document).ready(function(){
          $('.vote_action').click(function(e) {
              var postid = document.getElementById('vote_id').getAttribute('data-value');
              var button = $(this).attr("value");
              e.preventDefault();
              $.ajax({
                type: 'POST',
                url: '{% url "vote" %}',
                data: {
                  postid: postid,
                  csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),
                  action: 'postvote',
                  button: button,
                },
                success: function(json){
                  if (json.length < 1 || json == undefined) {
                    //empty
                  }
                  document.getElementById("points").innerHTML = json['result']
                },
                error: function(xhr, errmsg, err) {}
              })
            })
          })
        </script>

urls.py

urlpatterns = [
    path('vote/', views.post_vote, name='vote' ),
]

views.py

@login_required
def post_vote(request):
    if request.POST.get('action') == 'postvote':
        # get information from request about what item id it is
        id = int(request.POST.get('postid'))
        # And also which button was pressed
        button = request.POST.get('button')
        post = Posts.objects.get(id=id)

        if button == 'downvote_button':
            if not post.voters.filter(id=request.user.id).exists():
                post.voters.add(request.user)
                post.votes +=1
                post.points -=2
                post.save()

        elif button == 'upvote_button':
            if not post.voters.filter(id=request.user.id).exists():
                post.voters.add(request.user)
                post.votes +=1
                post.points +=2
                post.save()

        # return result
        post.refresh_from_db()
        result = post.points
        return JsonResponse({'result':result})
    pass

Sorry for the longest post ever! I've tried to cut down where possible and leave the essential information. Does anyone have any ideas?


Solution

  • I seem to have it working now using the following method which I came across on another post.

    In index.html I have changed:

    csrfmiddlewaretoken: $('input[name=csrfmiddlewaretoken]').val(),

    to

    csrfmiddlewaretoken: '{{ csrf_token }}',

    I am not sure if this is the correct way of solving this problem and will have to wait to see if it works when the site is eventually live. Any opinions are welcome.