I'm trying to implement a like functionality in my Django app using AJAX but, when I try to do that I'm getting an POST http://localhost:8000/forum/like/ 404 (Not Found). All I wanna do is to add/remove users from the likes list without refreshing the entire page.
views.py
#require_POST
def toggle_like(request):
if request.method == "POST":
user = request.user
slug = request.POST.get('slug', None)
question = get_object_or_404(Question, slug=slug)
if question.likes.filter(id=user.id).exists():
question.likes.remove(user)
else:
question.likes.add(user)
context = {'likes-count': question.likes.count}
return HttpResponse(json.dump(context), content_type='application/json')
urls.py
from django.urls import path
from . import views
app_name = 'forum'
urlpatterns = [
path('like/', views.toggle_like, name='toggle-like'),
]
question.html
{% block javascript %}
<script>
$('#like').click(() => {
$.ajax({
method: 'POST',
url: "{% url 'forum:toggle-like' %}",
data: {
'slug': $(this).attr('name'),
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
dataType: 'json',
success: (response) => {
alert(response.message);
},
error: (response, error) => {
alert(response.responseText);
}
})
})
</script>
{% endblock %}
{% block content %}
<p>Likes: {{ question.likes.count }} <input type="button" id="like" name="{{ question.slug }}" value="Like" /></p>
{% endblock %}
Related
I just started with ajax but can't seem to find the fix for this. I think it might have to do with the comment_id vs the blog_id. (followed this tutorial: https://www.youtube.com/watch?v=VoWw1Y5qqt8&list=PLKILtxhEt4-RT-GkrDkJDLuRPQfSK-6Yi&index=39&ab_channel=AbhishekVerma).
This is what my views.py looks like
def like_comment(request):
comment = get_object_or_404(Comment, id=request.POST.get("comment_id"))
blog = get_object_or_404(BlogPost, id=request.POST.get("blog_id"))
comments = Comment.objects.filter(post=blog, reply=None)
if request.user in comment.likers.all():
comment.likers.remove(request.user)
else:
comment.likers.add(request.user)
context = {
"comments": comments,
"blog_post": blog,
"body": markdown2.markdown(blog.body),
"comment_form": CommentForm(),
}
if request.is_ajax():
html = render_to_string('blog/like_section.html',
context, request=request)
return JsonResponse({'form': html})
This is a snippet of my HTML
{% if request.user.is_authenticated %}
<form action={% url 'like_comment' %} method="POST">
{% csrf_token %}
{% if user in comment.likers.all %}
<input type="hidden" name="blog_id" value=" {{ blog_post.id }}">
<button type="submit" id="like" name="comment_id" value="{{ comment.id }}">Like</button>
{% else %}
<input type="hidden" name="blog_id" value=" {{ blog_post.id }}">
<button type="submit" id="like" name="comment_id" value="{{ comment.id }}">Dislike</button>
{% endif %}
{% else %}
<div><small class="comment_time">Login to Like</small></div>
{% endif %}
</form>
</div>
<small class="comment_time">{{ comment.total_likes }}
Likes</small>
And this is the javascript:
$(document).ready(function (event) {
$(document).on('click', '#like', function (event) {
event.preventDefault();
var pk = $(this).attr('value');
$.ajax({
type: "POST",
url: '{% url "like_comment" %}',
data: { 'blog_id': pk, 'csrfmiddlewaretoken': '{{ csrf_token }}' },
dataType: 'json',
success: function (response) {
$('#like_section').html(response['form'])
console.log($('#like_section').html(response['form']));
},
error: function (rs, e) {
console.log(rs.responseText);
},
});
});
});
I'm getting the following error:
Picture
I would start to check if the request header contains HTTP_X_REQUESTED_WITH='XMLHttpRequest'. You can do that with the debug function of the browser (e.g. firefox). Maybe your JS library does not send this header.
see the Django documentation:
https://docs.djangoproject.com/en/1.11/ref/request-response/#django.http.HttpRequest.is_ajax
def is_ajax(self):
return self.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
HttpRequest.is_ajax():
Returns True if the request was made via an XMLHttpRequest, by checking the HTTP_X_REQUESTED_WITH header for the string 'XMLHttpRequest'. Most modern JavaScript libraries send this header. If you write your own XMLHttpRequest call (on the browser side), you’ll have to set this header manually if you want is_ajax() to work.
If a response varies on whether or not it’s requested via AJAX and you are using some form of caching like Django’s cache middleware, you should decorate the view with vary_on_headers('X-Requested-With') so that the responses are properly cached.
I am trying to post user geolocation to Django class based view. Apparently, javascript is not so friendly to me. How can I post user geolocation to UserProfileView class based view in django, ajax?
<body>
<div>
<div>
<strong>Current Position: </strong> {{ profile.user_location }}<br/>
</div>
<label for="locations-status">Enable Location?</label>
<input type="checkbox" id="locations-status">
<form id="location_form" method="POST" action="{% url 'rent_app:add-location' %}">
{% csrf_token %}
<button type="button" id="send-my-url-to-django-button">Send URL to Django View</button>
</form>
{% block js %}
<script>
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", "{{ csrf_token }}");
}
}
});
if ("geolocation" in navigator) {
navigator.geolocation.getCurrentPosition(
function (position) {
console.log('Position has been set successfully');
console.log(position.coords);
dataToSend = {
"permission": $("input[name=locations-status]").is(':checked'),
"user_location": position,
};
});
}
$("#send-my-url-to-django-button").click(function() {
$.ajax({
type: "POST",
dataType: 'json',
url: "{% url 'rent_app:add-location' %}",
data: JSON.stringify(dataToSend),
success: function (msg) {
console.log('Succeeded!');
},
error: function (err) {
console.log('Error!');
}
});
}, function (error) {
console.log('Position could not be obtained.');
}
);
</script>
{% endblock %}
</body>
views.py:
class UserProfileView(View):
form_class = UserProfileModelForm
template_name = "user_profile.html"
def get(self, *args, **kwargs):
form = self.form_class()
user_locations = UserProfile.objects.user_location()
return render(self.request, self.template_name,
{"form": form, "user_location": user_locations})
def post(self, *args, **kwargs):
if self.request.is_ajax and self.request.method == "POST":
form = self.form_class(self.request.POST)
if form.is_valid():
instance = form.save()
ser_instance = serializers.serialize('json', [ instance, ])
# send to client side.
return JsonResponse({"instance": ser_instance}, status=200)
else:
return JsonResponse({"error": form.errors}, status=400)
return JsonResponse({"error": ""}, status=400)
The context is {"form": form, "user_location": user_locations}) you don't have any profile passed in the context. I think you need to use {{ user_location }} instead of {{ profile.user_location }}
Just make the javascript work. Thank you, that would be helpful.
Having a tough time with this. I'm sending some data via Ajax to my Flask server route where it is being processed, with hopes to then render a new template with the processed data. The data seems to be flowing fine from my Javascript to my Flask server. (I am using JSGlue for Flask.url_for.) But as soon as it gets to "return render_template" it just dies. I get no traceback errors or anything. I've tried print() and console.log all over the place to get some kind of idea of what is killing it, but so far I've come up empty. Am I missing something obvious?
mypage.js
let c_list = [1,2,3....];
$.ajax({
url: Flask.url_for('get_genres'),
type: "POST",
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(c_list),
success: function (data) {
console.log(data);
}
})
init.py
#app.route('/get_genres', methods=["GET", "POST"]
def get_genres():
if request.method == "POST":
categories = request.json
c = Querybuilder()
genres = c.genres_from_c(categories)
return render_template("genres.html", genres=genres)
index.html
<head>
{{ JSGlue.include() }}
</head>
<body>
{% block body %}
{% endblock %}
</body>
genres.html
{% extends "index.html" %}
{% block body %}
<div class="genre_list">
{% for genre in genres %}
<a href="#" src="{{ genres[genre] }}" class="unclicked" onclick="toggleClicked(this)">
<p>{{ genre }}</p></a>
{% endfor %}
NEXT
</div>
{% endblock %}
After A LOT of digging around, I finally managed to find a solution to this issue. Adding a success function to the ajax call that redirects to another route.
mypage.js
$.ajax({
url: Flask.url_for('genre_picks'),
type: "POST",
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(genres),
success: function(response) {
window.location.href = response.redirect
}
});
init
#app.route('/genre_picks', methods=["POST", "GET"])
def genre_picks():
if request.method == "POST":
genres = request.json
return jsonify({'redirect': url_for("example", path=genres)})
#app.route('/example/<path>')
def example(path):
genres = path
return render_template("example.html", genres=genres)
HTML
{% if todo_array %}
<ul>
{% for TodoList in todo_array %}
<li class="listItems" name="listItem" id="item{{ forloop.counter }}" onClick = "myFunction({{ forloop.counter }})" >
{{ TodoList.todo_text }}
</li>
{% endfor %}
</ul>
{% else %}
<p> Add some Todo's !! </p>
{% endif %}
Javascript
var csrftoken = getCookie('csrftoken');
function myFunction(value){
console.log("clicked")
$.ajaxSetup({
headers: { "X-CSRFToken": getCookie("csrftoken") },
type:"POST",
{% load static %}
url:"{%url 'home'%}",
data: {
id : value
},
success: function(data) {
console.log('success',data);
},
});
}
Python
def home(request):
if request.method == 'POST':
todelete = request.POST.get('id')
print(todelete)
return render(request, 'home/mainList.html', context)
I'm trying to send the ID from html using javascript into python by making an ajax call. However the post data isn't working. How can I fix my code?
Edit.
Getting a server internal error 500 now.
Urls.py
urlpatterns = [
path('', views.home, name='home'),
path('logout', views.logout_attempt, name='logout')
]
In my users page, i have in place editing with ajax. And when i click edit, it works fine. But when i submit the form, it don't do anything. When i checked, this is the error:
CSRF verification failed. Request aborted.
So, how do I place {% csrf_token %} in my javascript? Please advice.
Thank you.
edit.js:
function bookmark_edit() {
var item = $(this).parent();
var url = item.find(".title").attr("href");
item.load("/save/?ajax&url=" + escape(url), null, function () {
$("#save-form").submit(bookmark_save);
});
return false;
}
$(document).ready(function () {
$("ul.bookmarks .edit").click(bookmark_edit);
});
function bookmark_save() {
var item = $(this).parent();
var data = {
url: item.find("#id_url").val(),
title: item.find("#id_title").val(),
tags: item.find("#id_tags").val()
};
$.post("/save/?ajax", data, function (result) {
if (result != "failure") {
item.before($("li", result).get(0));
item.remove();
$("ul.bookmarks .edit").click(bookmark_edit);
}
else {
alert("Failed to validate bookmark before saving.");
}
})
return false;
}
save_form.html:
<form id = "save-form" method="post" action="/save/">
{% csrf_token %}
{{form.as_p}}
<input type="submit" value="Save" />
</form>
user_page.html:
{% extends "base.html" %}
{% block external %}
<script type = "text/javascript" src="{% static "assets/js/bookmark_edit.js" %}"></script>
{% endblock %}
{% block title %} {{username}} {% endblock %}
{% block head %} Bookmarks for {{username}} {% endblock %}
{% block content %}
{% include "bookmark_list.html" %}
{% endblock %}
view.py:
#login_required(login_url='/login/')
def bookmark_save_page(request):
ajax = request.GET.has_key('ajax')
if request.method == 'POST':
form = BookmarkSaveForm(request.POST)
if form.is_valid():
bookmark = _bookmark_save(request, form)
if ajax:
variables = RequestContext(request, {
'bookmarks':[bookmark],
'show_edit':True,
'show_tags':True
})
return render_to_response('bookmark_list.html', variables)
else:
return HttpResponseRedirect('/user/%s/' % request.user.username
)
else:
if ajax:
return HttpResponseRedirect('failure')
elif request.GET.has_key('url'):
url = request.GET['url']
title = ''
tags = ''
try:
link = Link.objects.get(url=url)
bookmark = Bookmark.objects.get(
link=link,
user = request.user
)
title = bookmark.title
tags = ' '.join(
tag.name for tag in bookmark.tag_set.all()
)
except ObjectDoesNotExist:
pass
form = BookmarkSaveForm({
'url':url,
'title':title,
'tags':tags
})
else:
form = BookmarkSaveForm()
variables = RequestContext(request, {
'form': form
})
if ajax:
return render_to_response(
'bookmark_save_form.html',
variables
)
else:
return render_to_response('bookmark_save.html',variables)
You are not sending the server generated csrf_token for the POST to verify the validity of the data. Hence the error.
As a part of the data part of the request, you need to send the token
csrfmiddlewaretoken: '{{ csrf_token }}'
Something like this
var data = {
url: item.find("#id_url").val(),
title: item.find("#id_title").val(),
tags: item.find("#id_tags").val(),
csrfmiddlewaretoken: '{{ csrf_token }}'
};
Or you could simply do:
var data = $('form').serialize()
if you want to send the whole form as a dictionary
var csrftoken = Cookies.get('csrftoken');
xhr.setRequestHeader("X-CSRFToken", csrftoken);
enter link description here
This is what I use. Not sure if it's applicable in your situation though.
// sending a csrftoken with every ajax request
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}
$.ajaxSetup({
crossDomain: false, // obviates need for sameOrigin test
beforeSend: function(xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", $.cookie('csrftoken'));
}
}
});