A. Atiyah
A. Atiyah

Reputation: 555

My ajax post request gets 403 forbidden by django

I was trying to implement on keyup search with django and jquery following this video

but when I try the code everytime it returns forbidden 403!

the html page:

<div class="search-input">
  <form>
    {% csrf_token %}
    <button>بحـث</button>
    <input
      type="text"
      name="q"
      id="search"
      placeholder="Est: Game of thrones, Vikings or Deadpool"
    />
  </form>
</div>
<div class="search-results"></div>

urls.py:

path('search/', views.search_titles, name='search')

views.py:

def search_titles(request):
    if request.method == 'POST':
        search_text = request.POST['search_text']
    else:
        search_text = ''

    search_results = Media.objects.filter(
        is_published=True, title__contains=search_text)[:5]

    context = {
        'search_results': search_results
    }

    return render(request, 'partials/_search_results.html', context)

the jquery file:

$("#search").on("keyup", function() {
    $.ajax({
      type: "POST",
      url: "/search/",
      data: {
        search_text: $("#search").val(),
        csrfmiddlewaretoken: $("input[name=csrfmiddlewaretoken]").val()
      },
      success: searchSuccess,
      dataType: "html"
    });
  });

  function searchSuccess(data, textStatus, jqXHR) {
    $("search-results").html(data);
  }
});

search_results.html ( that i don't even know the reason of )

{% if search_results.count > 0 %} {% for result in search_results %}
<li>
  <a href="#">{{ result.title }}</a>
</li>
{% endfor %} {% else %}
<li>Nothing to show</li>
{% endif %}

Upvotes: 1

Views: 1388

Answers (1)

Sam
Sam

Reputation: 2084

This is likely happening because you are not properly setting up AJAX to pass your CSRF token. The Django docs have a great section on how to set this up. Here's the short story.

First, you'll need to acquire the token:

Here's how to do it if CSRF_USE_SESSIONS and CSRF_COOKIE_HTTPONLY in your settings are False:

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

// using jQuery
function getCookie(name) {
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') {
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) {
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) {
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            }
        }
    }
    return cookieValue;
}
var csrftoken = getCookie('csrftoken');

OR, Here's how to do it if CSRF_USE_SESSIONS or CSRF_COOKIE_HTTPONLY in your settings are True:

{% csrf_token %}
<script type="text/javascript">
// using jQuery
var csrftoken = jQuery("[name=csrfmiddlewaretoken]").val();
</script>

IN BOTH CASES, you'll also need to set up the token on your AJAX request:

function csrfSafeMethod(method) {
    // these HTTP methods do not require CSRF protection
    return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken);
        }
    }
});

Upvotes: 1

Related Questions