My ajax post request gets 403 forbidden by django - 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>
{{ result.title }}
</li>
{% endfor %} {% else %}
<li>Nothing to show</li>
{% endif %}

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);
}
}
});

Related

How can I send a CSRF token in a form?

I included a Vue form component in one of my Django templates. Now, I would like to send a CSRF token along with the data, since Django views require a CSRF token. Is there any way I can include it in my Vue form?
Here is my component:
<template>
<form #submit.prevent="formSubmit()">
<input type="text" class="form-control" v-model="amount">
<br>
<input type="text" class="form-control" v-model="price">
<br>
<button class="btn btn-primary" style="width: 100%">BUY</button>
</form>
</template>
<script>
import axios from 'axios'
export default {
mounted() {
console.log('Component mounted.')
},
data() {
return {
name: '',
description: '',
output: ''
};
},
methods: {
formSubmit() {
let currentObj = this;
axios.post('MY_URL', {
price: this.price,
amount: this.amount,
})
.then(function (response) {
currentObj.output = response.data;
}.bind(this))
.catch(function (error) {
currentObj.output = error;
});
},
}
}
</script>
First, acquire the token from the csrftoken cookie:
function getCookie(name) {
let cookieValue = null;
if (document.cookie && document.cookie !== '') {
const cookies = document.cookie.split(';');
for (let i = 0; i < cookies.length; i++) {
const cookie = cookies[i].trim();
// 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;
}
const csrftoken = getCookie('csrftoken');
...or from querying the document:
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value
Then, add the token value to your POST header:
axios.post('MY_URL', {
price: this.price,
amount: this.amount,
}, {
headers: {
'X-CSRFToken': csrftoken
}
})

Delete Specific Post from Front-end using ajax in Django (Class Based View)

I have lot of posts generated using loop in django, and want to delete specific post (like Facebook delete works). I am able to get id of post using jquery but i am not sure what I am doing wrong to delete post. I have also implemented delete function in class based view.
Delete Post Button
existing-dashboard.html
{% for i in all_posts %}
... ///rest of the code
<span class="username">{{ i.first_name }} {{i.surname}}
<span class="more" id="more-icon">{{i.post_id}}
<div class="more-menu" style="margin-top: 30px;">
<span class="delete" id="{{i.post_id}}">delete</span>
</div>
</span>
... /// rest of the code
</span>
{% endfor%}
Ajax
$('.delete').on('click', function(){
var post_id = $(this).attr('id');
alert(post_id)
$.ajax({
url: 'http://127.0.0.1:8000/existing-delete/' + post_id +'/',
type: 'DELETE',
data: {},
contentType: 'application/json',
dataType: 'text',
error:
function(result){
alert(result)
},
success:
function(result){
alert(result)
}
})
})
views.py
class ExistingStudentDashboard(TemplateView):
.../// rest of the code
def delete(self, request, pk, format=None):
post1 = Existing_student_posts.objects.filter(id = pk).first()
post2 = Future_student_posts.objects.filter(id = pk).first()
post3 = Teacher_posts.objects.filter(id = pk).first()
post4 = Employee_posts.objects.filter(id = pk).first()
if post1:
post1.delete()
elif post2:
post2.delete()
elif post3:
post3.delete()
else:
post4.delete()
get_context_data()
urls.py
path('existing-delete/,<int:pk>', views.ExistingStudentDashboard.as_view(), name = 'existing-delete'),
Getting Error in Console like bellow
Not Found: /existing-delete/61/
Browser Console Error
Browser Console Error
What I am doing wrong to delete post. Feel free to ask about more clarification. Any help will be appreciated :)
You have a typo in your path, change it to this
path('existing-delete/<int:pk>', views.ExistingStudentDashboard.as_view(), name = 'existing-delete'),
Edit:
Use this to get the csrf token in javascript
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]);
if (cookie.substring(0, name.length + 1) === (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
var csrftoken = getCookie('csrftoken');
Then while making the ajax request, pass that on the headers.
headers: {"X-CSRFToken":csrftoken }

reactjs/redux + django CSRF protection

I am trying to make an AJAX request from my reactjs frontend to my django backend but I am getting this error upon POST. I'm not sure how to properly pass CSRF tokens around for my form POST to work properly
Forbidden (CSRF token missing or incorrect.): /api/contact
[05/Nov/2016 03:43:14] "POST /api/contact HTTP/1.1" 403 2502
I created a react component and added it into my form
CSRF component
import React from 'react';
import $ from '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 = $.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;
}
const Csrf = () => {
let csrfToken = getCookie('csrftoken');
return (
<input type="hidden" name="csrfmiddlewaretoken" value={ csrfToken } />
);
};
export default Csrf;
Contact form component:
const ContactForm = ({ formOnChange, onFormSubmit, isFullNameValid, isEmailValid, isMsgValid }) => {
let rows = 10;
let tabindex = 8;
let isSubmitDisabled = !(isFullNameValid && isEmailValid && isMsgValid);
return(
<div className="form-wrapper">
<form className="contact-form" onChange={ formOnChange }>
<Csrf />
<input className={ isFullNameValid ? "" : "active" } type="text" name="fullname" placeholder="Full Name *" />
<div className="email-phone-group">
<input type="text" name="phonenumber" placeholder="Phone Number"/>
<input className={ isEmailValid ? "" : "active" } type="text" name="email" placeholder="Email *"/>
</div>
<textarea className={ isMsgValid ? "" : "active" } rows={ rows } tabIndex={ tabindex } name="message" placeholder="Message... *"/>
<button disabled={ isSubmitDisabled } className="contact-form-submit-btn" type="button" onClick={ onFormSubmit }>Submit</button>
</form>
</div>
);
};
My redux action calls this AJAX function
export function contactSubmission(contactSubmission) {
// thunk
return dispatch => {
console.log("contact form submitted");
console.log(contactSubmission);
$.ajax({
method: 'POST',
url: '/api/contact',
dataType: 'json',
success: payload => {
if (payload.error) {
return dispatch(contactSubmissionFailure());
} else {
return dispatch(contactSubmissionSuccess(payload));
}
},
error: payload => {
console.log("ajax error");
console.log(payload);
return dispatch(contactSubmissionFailure());
}
});
};
}
you should put the following code before $.ajax to send a CSRF code:
$.ajaxSetup({
headers: {"X-CSRFToken": getCookie("csrftoken")}
});
...THEN YOUR CODE
$.ajax({...});
You can notice that you have already set getCookie.
With this should work properly.

CSRF token missing or incorrect using Jquery

I have the following code below but I still get "CSRF token missing or incorrect." error. anyone spot what I have done wrong here?
<form method="post" action="" id="registration">
{{ form.as_p }}
<input type="submit" value="{% trans 'Submit' %}" />
</form>
<script>
$('#registration').submit(function(e){
e.preventDefault(); //prevent default form submit
$.ajax({
url: '/accounts/registerAjax/',
type: 'POST',
contentType: "application/json;charset=utf-8",
dataType: "json",
data: {
'csrfmiddlewaretoken': '{{ csrf_token }}',
'id_username': $("#id_username").val(),
'id_email': $("#id_email").val()
},
success: function() {
alert('Test');
},
error: function(errorThrown){
console.log(errorThrown);
alert('Error');
alert(errorThrown);
}
});
From the docs.
on each XMLHttpRequest, set a custom X-CSRFToken header to the value of the CSRF token.
As a first step, you must get the CSRF token itself. The recommended source for the token is the csrftoken cookie, which will be set if you’ve enabled CSRF protection for your views as outlined above.
// 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');
The above code could be simplified by using the jQuery cookie plugin to replace getCookie:
var csrftoken = $.cookie('csrftoken');

Django - Ajax error while saving form values

I have an Edit Form page which edits existing posts. i wanted to put a Preview link into this page. what i want is ; when i click preview link it must ;
take form element's current values and write them into my
Post_Preview Model.
then , ajax function must redirect to my *show_preview* page which i defined in views and urls.
and in show_preview page (preview.html) it must be rendered. (form's
current values)
this is how it must works. And here are my codes :
and my edit-form page:
<form method="post" action="">
{% csrf_token %}
<input type="hidden" id="post_owner" value="{{ post.owner }}"/></td>
<input type="hidden" id="post_id" value="{{ post.id }}"> </td>
{{ form.title }}
{{ form.body }}
Preview
<input type="submit" value="Save" style="cursor: pointer;"/>
</form>
ajax Function:
$(function(){
$('#preview').click(function() {
var title = $('#id_title').val();
var body = $('#id_body').val();
var owner = $('#post_owner').val(); //hidden value at form page
var id = $('#post_id').val(); //hidden value at form page
var ajaxOptions = {
type:'post',
url : '/admin/post/save_preview/', //save_preview's url
data : {
'title' : title,
'body' : body,
'owner' : owner,
'id' : id
},
success: function(){
window.open("/blog/"+owner+"/preview/"+id); //show_preview's url
},
error: function(){
alert('There is an Error'); //this is what i see when click preview link.
}
};
$.ajax(ajaxOptions);
});
});
my save_preview view:
def save_preview(request):
title = request.POST['title']
body = request.POST['body']
owner = request.POST['owner']
post_id = request.POST['id']
try:
preview = Post_Preview(id=post_id, title=title, body=body, owner=owner)
preview.save()
except:
pass
return HttpResponse(200)
my show_preview view:
def show_preview(request,post_id,username):
preview = Post_Preview.objects.get(id=post_id)
return render_to_response('preview.html',{'post': preview}, context_instance=RequestContext(request))
my related url lines:
url(r'^admin/post/save_preview/', view='save_preview' ,name='save_preview'),
url(r'^blog/(?P<username>[-\w]+)/preview/(?P<post_id>\d+)', view='show_preview', name='show_preview'),
When i click Preview link at edit-form page : it shows 'There is an Error' error; which is defined in ajax function.
thank you!
edit : there is more code before my ajax function in js file (which are related to django-ajax relation ):
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');
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function sameOrigin(url) {
// test that a given url is a same-origin URL
// url could be relative or scheme relative or absolute
var host = document.location.host; // host + port
var protocol = document.location.protocol;
var sr_origin = '//' + host;
var origin = protocol + sr_origin;
// Allow absolute or scheme relative URLs to same origin
return (url == origin || url.slice(0, origin.length + 1) == origin + '/') ||
(url == sr_origin || url.slice(0, sr_origin.length + 1) == sr_origin + '/') ||
// or any other URL that isn't scheme relative or absolute i.e relative.
!(/^(\/\/|http:|https:).*/.test(url));
}
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && sameOrigin(settings.url)) {
// Send the token to same-origin, relative URLs only.
// Send the token only if the method warrants CSRF protection
// Using the CSRFToken value acquired earlier
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
edit 2: when i add try/except blocks for save_preview ; i didnt throw popup error page. it redirected to save_preview page and threw and error :
Post_Preview matching query does not exist.
156. preview = Post_Preview.objects.get(id=post_id)
You're not sending the csrf token in $.ajax.