I have a html form like:
<form id="comment" action="{% url "url_name" ur.id %}" method="post">{% csrf_token %}
<textarea required="required" maxlength="255" rows="4" class="form-control" name="comment">
</textarea>
<button class="btn btn-default" onclick="add_comment(event)">Comment</button>
</form>
It is a html form and not django's form.
Here I have included csrf token in the form. I have post this form form javascript and now it gives me csrf verification failed error.
What am I missing here ? Is it mandatory to create form from django' form class to use csrf token ?
Need help
My js looks like:
function add_comment(event) {
event.preventDefault()
var form = document.getElementById('comment')
var url = form.action
var method = form.method
var form_data = new FormData(form)
fetch(url, {method: method, body: form_data})
}
and I am just rendering a template from my django view
When I see request network, csrf token and comment are passed as request payload ..
This GitHub issue suggests that you have to include the credentials, so that the CSRF cookie is sent with the request.
fetch(url, {method: method, body: form_data, credentials: 'include'})
I assume you're using AJAX to post the form. When posting forms with Django using AJAX you need to add the following to your Javascript before submitting the AJAX request:
$.ajaxSetup({
beforeSend: function(xhr, settings) {
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;
}
if (!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
More info can be found at https://docs.djangoproject.com/en/1.10/ref/csrf/#ajax
Related
I need to make a hyperlink in Django for a POST-request. For example, "Add to blacklist" in the menu. It's easy to do with a form with a submit button but I need a menu item not button. I found Javascript code for doing this but it gives me an error 403: CSRF token missing or incorrect. And I couldn't find understable for me information how to insert csrf-token into the Javascript function. I don't know Javascript, I write in Python.
Here's the function from https://ru.stackoverflow.com/questions/65237/Вызов-метода-post-через-ссылку:
<script type="text/javascript">
function postToUrl(path, params, method) {
method = method || "post";
var form = document.createElement("form");
form.setAttribute("method", method);
form.setAttribute("action", path);
for(var key in params) {
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", key);
hiddenField.setAttribute("value", params[key]);
form.appendChild(hiddenField);
}
document.body.appendChild(form);
form.submit();
}
</script>
Here's how I call it:
To blacklist
This is my view:
class AddToBlacklistView(View):
def post(self, request, watched_user_id, next_url=None, *args, **kwargs):
if not next_url:
next_url = '../profile.html/user_id{0}'.format(watched_user_id)
if request.user.is_authenticated:
try:
user = User.objects.select_related("profile").get(username=request.user)
watched_user = User.objects.select_related("profile").get(id=watched_user_id)
except User.DoesNotExist:
raise Http404
if watched_user.id == user.id:
return redirect(next_url)
if watched_user not in user.profile.blacklist.all():
user.profile.blacklist.add(watched_user)
user.save()
if watched_user.profile in user.profile.friends.all():
user.profile.friends.remove(watched_user.profile)
if user.profile in watched_user.profile.friends.all():
friendship = Friendship.objects.get(user=watched_user.profile, friend=user.profile)
if friendship.status != 3:
friendship.status = 2
friendship.save()
if watched_user in user.profile.bookmarks.all():
user.profile.bookmarks.remove(watched_user)
return redirect(next_url)
else:
return redirect(next_url)
I tried this and it didn't help:
<meta name="csrf-token" content="{{ csrf_token }}">
<script>
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});
</script>
I also tried to pass as params this and it didn't help:
csrfmiddlewaretoken: '{{ csrf_token }}'
Upd:
I also tried to add the decorator for a view and it continued to throw the same error:
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_protect
#method_decorator(csrf_protect)
def post ...
I also tried # method_decorator(ensure_csrf_cookie) on the view that renders the page with HTML that calls the Javascript function and I still get 403 error.
I also tried this code from https://docs.djangoproject.com/en/3.0/ref/csrf/ and it continued to throw the same 403 error.
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');
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);
}
}
});
Please help me!
I found a solution here:
submitting a hyperlink by GET or POST
I had to modify it because on my page there is a list of people with a menu for each one of them in such a way:
<form id="myform1_{{ message.recipient.user.id }}" method="post" action="/account/add_to_blacklist/watched_user_id{{ message.recipient.user.id }}/next={{ request.get_full_path }}" >
{% csrf_token %}
</form>
Add to blacklist
I'm trying to send ajax post requests to my server to add or remove objects by using just checkboxes (not form). Here is a screenshot of what I got visually:
https://pasteboard.co/IMHHSa6.png
When I click any of the checkboxes I got http500 (internal server error) as response. In cmd I see the error that says there is no matching query: app1.models.Influencer.DoesNotExist: Influencer matching query does not exist.
The thing is I'm pretty sure that the object with that id exists in the database. I spend much time inspecting Django's CSRF documentation and watching youtube videos about django-ajax examples. Here is my code:
views.py:
class InfluencerListView(LoginRequiredMixin, ListView):
model = Influencer
context_object_name = 'influencers' # not necessary, default is object_list
def post(self, request, *args, **kwargs):
inf_id = request.POST.get('inf.id')
list_id = request.POST.get('list.id')
i = Influencer.objects.get(id=inf_id)
l = InfluencerList.objects.get(id=list_id)
l.influencers.add(i)
data = {
'result' : 'some result'
}
return JsonResponse(data)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
logged_in_user = self.request.user
context['myLists'] = logged_in_user.lists.annotate(influencers_count=Count('influencers'))
return context
models.py:
class Influencer(models.Model):
# fields are not included for the sake of clarity
class InfluencerList(models.Model):
name = models.CharField('Name:', max_length=20, blank=False)
owner = models.ForeignKey(User, on_delete=models.CASCADE, related_name='lists')
influencers = models.ManyToManyField('Influencer', related_name='lists')
scripts.js
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 = 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;
}
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
function myFunc(_self) {
inf_id = _self.getAttribute('data-inf_id');
list_id = _self.getAttribute('data-list_id');
console.log(inf_id + " " + list_id); # I CAN SEE THOSE IDS IN CONSOLE AND THEY EXIST IN DB
var csrftoken = getCookie('csrftoken');
if(_self.checked == true){
console.log("checked!");
$.ajaxSetup({
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
$.ajax({
method: 'POST',
url: '/influencers',
data: {
'inf_id': inf_id,
'list_id': list_id,
'csrfmiddlewaretoken': csrftoken
},
dataType: 'json',
success: function (data) {
console.log("succes!");
}
});
}
else{
console.log("unchecked!");
}
}
I also added this line somewhere in my view file (where I put it doesn't matter as long as it's in the body since I'm not using any forms. Please correct me if I'm wrong):
<input type='hidden' name='csrfmiddlewaretoken' value='{{ csrf_token }}' />
i'm trying to add to the html page a form with js (like the html token {% csrf_token %} when loading the page does):
table += "<td><form action='' method='post'>";
table += "<input type='submit' value='Delete?' />";
table += "</form></td>;
$("#tbody").append(table);
my problem is that i get a csrf validation error:
Forbidden (403)
CSRF verification failed. Request aborted.
Help
Reason given for failure:
CSRF token missing or incorrect.
i tried to add a custom csrf token:
var buf = new Uint8Array(1);
window.crypto.getRandomValues(buf);
table += "<input type='hidden' name='csrfmiddlewaretoken' value='" + buf[0] + "'>";
but i still get an error.
i also have in my js file the following code (which i got from the django website - and i don't know how it actually works..):
//enable csrf post ajax
//This function gets cookie with a given name
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 functions below will create a header with csrftoken
*/
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 &&
(!(/^http:.*/.test(settings.url) || /^https:.*/.test(settings.url)))) {
// Only send the token to relative URLs i.e. locally.
xhr.setRequestHeader("X-CSRFToken", getCookie('csrftoken'));
}
}
});
is there a way to add a csrf token with js the way i tried or it can not be?
The Javascript code provided by django for csrftoken extraction assigns csrftoken value to a variable named csrftoken
You can access it anywhere by its variable name, like this:
table += "<input type='hidden' name='csrfmiddlewaretoken' value='" + csrftoken + "'>";
Make sure you've included the js provided by django in your page before accessing csrftoken
Also, as #Sander pointed out, if you're using inline JS you can directly use csrf_token template tag instead.
table += "{% csrf_token %}";
Is the js added as inline js to your django template?
In that case you can do:
table += "<td><form action='' method='post'>";
table += "{% csrf_token %}";
table += "<input type='submit' value='Delete?' />";
table += "</form></td>;
$("#tbody").append(table);
In Django Template Without using form i want to upload files to my web server. so for that i`m using javascript library called dropzonejs.
I exactly follow this tutorial bootstrap dropzonejs. I setup everything to run the demo.
You see i decided not to use form so obviously the problem csrf_token is missing when upload happens time.
My doubt is how to include csrf_token in javascript. ?
This is the information they added in their home page for how to add csrf token
sending - Called just before each file is sent. Gets the xhr object and the formData objects as second and third parameters, so you can modify them (for example to add a CSRF token) or add additional data.
Are you understand my question ? give me some idea to do that ?
You could either have the view CSRF exempt:
from django.views.decorators.csrf import csrf_exempt
class YourView(models.View):
#csrf_exempt
def dispatch(self, *args, **kwargs):
return super(YourView, self).dispatch(*args, **kwargs)
The JavaScript config would probably look something similar to this:
(function($){
$(function(){
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) {
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
crossDomain: false,
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
}
});
});
})(jQuery);
Here's what I am looking for.
I have an UpdateView, which renders the form from CreateView with fields loaded from database. Instead my edit form has readonly html attribue. So what I need is to drop readonly on click on the form field and when i enter new value it will be automaticaly updated when cursos moves to the next field.
How do i handle POST actions with out submit button?
you can use JavaScript(Jquery) to do so, blur event
EDITED: about CSRF verification,see https://docs.djangoproject.com/en/dev/ref/contrib/csrf/#ajax
about $.post see:https://api.jquery.com/jQuery.post/
template.html
<script type="text/javascript" src="/media/js/jquery-1.10.2.min.js"></script>
<script>
// 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;
}
$(document).ready(function(){
$("#myinput").blur(function(){
var csrftoken = getCookie('csrftoken');
$.ajaxSetup({
beforeSend: function(xhr) {
xhr.setRequestHeader("X-CSRFToken", csrftoken);
}
});
$.post('/link-to-fun/',{"value":value});
});
});
</script>
<input type="text" id="myinput">
url.py
write a special url(/link-to-fun/) to function in views.py
url(r'^link-to-fun$', views.change_db_value),
views.py
def change_db_value(request):
value = request.POST.get('value','')
# database operation