Django Ajax Post Request by Using Checkbox in CBV - javascript

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 }}' />

Related

Error :Forbidden (CSRF token missing or incorrect.) while using django rest framework

I use in my study project django rest framework.I get an error 403 Forbidden (CSRF token missing or incorrect, when I try to save using the POST method. Here is my code html
<form id = "product_form" method = "post">
{% csrf_token %}
<input type = "hidden" name = "id" id = "id">
<p>Назвние:<input name = "name" id = "name"></p>
<p><input type = "reset" value = "Oчистить"></p>
<input type = "submit" value = "Сохранить">
</form>
Here is my code js:
let productUpdater = new XMLHttpRequest();
productUpdater.addEventListener('readystatechange', () => {
if (productUpdater.readyState == 4) {
if ((productUpdater.status == 200) || (productUpdater.status == 201)) {
listLoad();
name.form.reset();
id.value = '';
} else {
window.alert(productUpdater.statusText)
}
}
}
);
name.form.addEventListener('submit', (evt) => {
evt.preventDefault();
// let vid = id.value, url, method;
let vid = id.value;
if (vid) {
url = 'http://127.0.0.1:8000/books/api_category/' + vid + '/';
method = 'PUT';
} else {
url = 'http://127.0.0.1:8000/books/api_category/';
method = 'POST';
}
let data = JSON.stringify({id: vid,nameCategory: name.value});
productUpdater.open(method, url, true);
productUpdater.setRequestHeader('Content-Type', 'application/json');
productUpdater.send(data);
})
Here is my views.py:
#api_view(['GET', 'POST'])
def api_products(request):
if request.method == 'GET':
productsAll = CategoryMaskarad.objects.all()
serializer = CategorySerializer(productsAll, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = CategorySerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
#api_view(['GET', 'PUT', 'PATCH', 'DELETE'])
def api_rubric_detail(request, pk):
product = CategoryMaskarad.objects.get(pk=pk)
if request.method == 'GET':
serializer = CategorySerializer(product)
return Response(serializer.data)
elif request.method == 'PUT' or request.method == 'PATCH':
serializer = CategorySerializer(product, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
product.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
Here is my urls.py:
path('api_category/<int:pk>/', api_rubric_detail),
path('api_products/', api_products),
path('api/drf-auth/', include('rest_framework.urls'))
I added the last path and logged in. In the api interface it became possible to add to the api using the post method, but with the help of js in my html I cant add data.Help me, please
I have this option. He is work.I added to js file:
name.form.addEventListener('submit', (evt) => {
evt.preventDefault();
// let vid = id.value, url, method;
let vid = id.value, url, method;
if (vid) {
url = 'http://127.0.0.1:8000/books/api_category/' + vid + '/';
method = 'PUT';
} else {
url = 'http://127.0.0.1:8000/books/api_category/';
method = 'POST';
}
let data = JSON.stringify({id: vid, nameCategory: name.value});
productUpdater.open(method, url, true);
productUpdater.setRequestHeader('Content-Type', 'application/json');
productUpdater.setRequestHeader('X-CSRFToken', csrftoken);
productUpdater.send(data);
})
and I added to html file:
<script>
const csrftoken = document.querySelector('[name=csrfmiddlewaretoken]').value;
</script>
when passing data in form to a django rest framework, you do not add the csrf_token tag before forms, rather you pass it as a header when sending api post on your endpoint.
Add this line after
try adding this function into your codes to get the values of csrftoken
let 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();
if(cookie.substring(0, name.length+1)===(name+'=')){
cookieValue = decodeURIComponent(cookie.substring(name.length+1));
break;
}
}
}
return cookieValue;
}
and then change the value you use in x-csrf-token and make it
productUpdater.setRequestHeader('Content-Type', 'application/json');
productUpdater.setRequestHeader('X-CSRF-Token', getCookie("csrftoken"));

How to use csrf-token in POST-hyperlink?

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

Django + Ajax + Facebook API 403 FORBIDDEN

I am trying to apply Facebook Login API in django project. I planned to use Facebook username and default password(as far as django doesn't allow to create users without pass) and authenticate via ajax.
FB.api('/me', function(response) {
alert(response.name); // it's fine, it's there
ajaxPost('/authfb/', {'username': response.name}, function(){ });
});
What I get in log is :
Failed to load resource: the server responded with a status of 403 (FORBIDDEN)
And in alert message:
POST /authfb/ 403 FORBIDDEN
undefined
I am using django-ajax with decorator, but it works for me in all other parts of code.
views.py:
#ajax
def authfb(request):
if request.method == "POST":
username = request.POST.get('username')
password = '112358'
user = auth.authenticate(username=username, password=password)
if user is not None:
auth.login(request, user)
username = auth.get_user(request).username
print ('logged in succesfully')
return redirect("/user/%s/" % username)
else:
print("The username and password were incorrect.")
error_message_login_page = 'you do not exist'
return render(request, 'blog/facebook.html', {'error_message_login_page':error_message_login_page})
else:
print("whatever")
In similar questions csrf security is often pointed as issue. So I tried this js code, which might be right, but still didn't help:
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');
$.ajaxSetup({
headers: { "X-CSRFToken": getCookie("csrftoken") }
});
EDIT:
def fblogin(request):
if request.user.is_authenticated():
username = auth.get_user(request).username
return redirect("/user/%s/" % username)
print(username)
else:
return render(request, 'blog/facebook.html', {})`
Try this instead of yours.
function getCookie(name) {
var value = "; " + document.cookie;
var parts = value.split("; " + name + "=");
if (parts.length == 2) return parts.pop().split(";").shift();
}
Also
ajaxPost('/authfb/', {'username': response.name, 'csrfmiddlewaretoken': getCookie('csrftoken')}, function(){ });
Update
Add
{% csrf_token %}
somewhere inside body of facebook.html

AJAX: POST data to a different url

I'm creating an event registration page.
On this page, users need to be able to search for a database item so it can be registered to this event. Therefore, the POST request must be submitted to a different URL than what the user is on, so that it doesn't interfere with the form wizard sequence.
This is my javascript:
(document).ready(function() {
$('#primary_artist_lookup').on('input', function(){
console.log("Listener success");
var searchItem = $('#primary_artist_lookup').val();
$.ajax({
url : $('#lookupLink').val(),
type : "POST", //http method
data : searchItem,
dataType: "json",
// handle a successful response
success : function (json) {
console.log(json); // log the returned json to the console
console.log("success"); // another sanity check
},
// handle a non-successful response
error : function(xhr,errmsg,err) {
$('#results').html("<div class='alert-box alert radius' data-alert>Oops! We have encountered an error: "+errmsg+
" <a href='#' class='close'>×</a></div>"); // add the error to the dom
console.log(xhr.status + ": " + xhr.responseText); // provide a bit more info about the error to the console
}
});
});
The url is a hidden html value that maps to the url I am trying to POST the data to:
<p hidden id="lookupLink">{% url "Users:lookup" %}</p>
There is an additional js portion to submit a CSRF token to Django for security purposes:
// CSRF VALIDATION //
// 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));
}
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);
}
}
});
return false;
});
When I try to use this ajax function, it doesn't post to the url I request, but rather the page that the users are on. What am I doing wrong?
use text() instead:
url : $('#lookupLink').text(),
and data should be an object:
data : { searchItem : searchItem },

how to apply csrf_token in django

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

Categories