I'm making a like button for a post in django. What I need is that when the like button is clicked, the function is executed, but I need the page not to be reloaded (To later use javascript). To do that I return a jsonresponse() instead of a return render. But the real problem is that it redirects me to the page that I show in the photo. The page is not reloaded. as I want it. but I don't want it to show me the blank page with the jsonresponse data (like this photo).I want to stay in the same page without reload.
My view function:
def liking (request, pk):
posts = get_object_or_404(Post, id = pk)
if request.user in posts.likes.all():
posts.likes.remove(request.user)
else:
posts.likes.add(request.user.id)
likes_count = posts.likes.all().count()
print(f'likes_count = {likes_count}')
data= {
'likes_count': likes_count,
}
#return redirect ('index')# This is commented
return JsonResponse(data, safe=False, status=200 )
You can use AJAX. Simply place the code below in the template and trigger it with buttons.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.1/jquery.min.js"></script>
<script>
function get_likes(pk){
$.ajax({
url: '{% url "url-name" pk %}',
type: 'GET',
success: function (res) {
var likes = JSON.parse(res);
return likes["likes_count"]
}
});
}
</script>
If you need to post any data, you can use the lines below.
function get_likes(pk){
$.ajax({
url: '{% url "url-name" pk %}',
type: 'POST',
data: {
csrfmiddlewaretoken: "{{ csrf_token }}",
data1:"data",
data2:"data"
},
success: function (res) {
var likes = JSON.parse(res);
return likes["likes_count"]
}
});
}
You can add the following lines in your function to use the posted data on the django side.
data1 = request.POST.get("data1")
data2 = request.POST.get("data2")
After trying for a while, I found the problem. It had nothing to do with the ajax request or a fetch, which is what I ended up using. It was simply that I had the url of the views.py function in the href="" and for this reason the white screen came out with the jsonresponse() data:
I had to change:
<a class="btn btn-dark like" id="like_button" href="{% url 'liking' post.id %}"> Like</a>
So:
<a class="btn btn-dark like" id="like_button" href="#"> Like</a>
Thanks for all the answers!
Related
I have a sort of twitter like button function in my app such that, when the button is clicked, it triggers an AJAX call and performs the action specified in the views. However, when i click the button, it does not perform action in views. The code reaches the 'like view' but does not execute anything after 'if request.POST:'. Please help.
Menu.html
<form action="{% url 'like'%}" id="plt_{{menu.id}}" data-id="{{menu.id}}" method="post">
{%csrf_token%}
<input name="menu_id" type="hidden" value="{{ menu.id }}">
<div class="like-button" id="btn_{{menu.id}}"></div>
</form>
<script>
$('.like-button').on('click', function () {
var id = $(this).attr('id');
id = id.replace('btn_','');
$(this).toggleClass('animate').promise().done(function () {
var link = $("#plt_"+id).attr('action')
$.ajax({
type: 'POST',
url: link,
headers: {'X-CSRFToken': '{{ csrf_token }}'},
})
});
});
</script>
Views.py
def like(request):
print('reached') //this prints
if request.POST:
menu = Menu.objects.get(pk=request.POST.get('menu_id'))
//execute code to like
return HTTPResponse('')
Maybe you want to check
if request.is_ajax() and request.method== "POST":
request.POST is a dict .Empty here because body is empty in your request.
Empty dicts are treated like False by python like
if {}:
print("Hello World")
Above won't print anything
But below works
if {"hi" : "there"}:
print("Hello World")
And docs suggests this check is wrong if request.POST:
It’s possible that a request can come in via POST with an empty POST
dictionary – if, say, a form is requested via the POST HTTP method but
does not include form data. Therefore, you shouldn’t use if
request.POST to check for use of the POST method; instead, use if
request.method == "POST" (see HttpRequest.method).
It is fairly simple, use serialize() of jquery. Serialize function will take all the values from the form, even csrftokenmiddleware which is hidden input type. So, doing so you will be able to handle post request successfully. Use sthg like this:
<script>
$('.like-button').on('click', function () {
var id = $(this).attr('id');
id = id.replace('btn_','');
$(this).toggleClass('animate').promise().done(function () {
var link = $("#plt_"+id).attr('action');
var data = $("#plt_"+id).serialize(); // It will serialize all form data
$.ajax({
type: 'POST',
url: link,
data: data
});
});
});
</script>
In views.py do as you do for other request. serialize()
I am creating simple "rock paper scissors" game with some css animations and so on, where most of the stuff happens in javascript, as learning JS is what I am focusing on mostly at the moment.
User vs computer match also happens in javascript. When match is finished I am assigning users earned exp(points) to new variable.
What I am trying to do now is sending that data (earned exp) to the views, so I can save it back in a database (users.exp).
I think jQuery ajax or fetch api should do that if I am right but after hours of trying I probably just don't get it.
Any1 can give me some tips, explanation? Not just solution please.
Views:
#login_required
def profile(request):
if request.user.is_authenticated:
user = request.user
userObj = Profile.objects.filter(user=user)
usersLevel = userObj[0].level
usersPoints = userObj[0].points
context = {
'usersLevel': usersLevel,
'usersPoints': usersPoints,
}
return render(request, 'rps_app/game.html', context)
else:
print('No user logged in!')
return render(request, 'rps_app/game.html')
This is my template where Iam loading users data:
<script type="text/javascript">
var usersLevel = '{{usersLevel|safe}}';
var usersPoints = '{{usersPoints|safe}}';
</script>
js:
let users_level = Number(usersLevel);
let users_points = Number(usersPoints);
progressbar.style.width = `${users_points}%`;
...
javascript:
$(document).ready(function(){
$('#btn-ajax').click(function(){
$.ajax({
url: 'http://127.0.0.1:8000/game',
csrfmiddlewaretoken: "{{ csrf_token }}",
type: 'get',
success: function(data) {
console.log(data);
alert(data);
},
failure: function(data) {
alert('Your code is crap mate');
}
});
});
})
************ . E D I T E D . ***********
Thats what I got now:
js:
$(document).ready(function(){
$('#btn-ajax').click(function(){
$.ajax({
url: 'http://127.0.0.1:8000/test/earned_exp=100/',
csrfmiddlewaretoken: "{{ csrf_token }}",
success: function(data) {
alert('succes');
},
failure: function(data) {
alert('Your code is crap mate');
}}); });})
views:
def pass_variable(request, earned_exp=None):
some_variable = request.GET.get('earned_exp')
console.log(some_variable)
return HttpResponse('<h1>ok.{}</h1>'.format(earned_exp))
url:
path('test/<earned_exp>/', user_views.pass_variable, name='pass_variable'),
You can pass variables as URL parameters and get them through the request object.
$.ajax({
url: 'mycoolwebsite.com/path/?earned_xp=100'
success: function(e){
alert("success");
},
error: function(e){
alert("error")
}
});
class MyView(View):
def get(self, request):
xp = request.GET.get("earned_xp")
# do whatever you want with the XP now.
In case you want to send multiple URL parameters, you can seperate them by & here's an example url
https://example.com/?hello=world&goodbye=coding
Currently my button functions, but I've placed it inside of a django for loop. I'd like to move the js logic to a separate file, but first I need to give it a better name. Here is a snippet of my code:
{% for post in posts %}
.....
<script type="text/javascript">
function toggleLike{{post.id}}(){
$.ajax({
url: "{% url 'photo_blog-post_like_api' post.id %}",
success: function(data) {
$("#likeCount{{post.id}}").html(data.like_count + ' likes');
$('#imageElement{{post.id}}').html(data.img);
}
});
};
</script>
<a id=imageElement{{post.id}} onclick="toggleLike{{post.id}}()"><img src="/media/nav_buttons/liked.svg" height="17" width="17"></a>
....
<post info here>
....
{% endfor %}
When I remove the {{post.id}} from the function name, and onclick call, the button only functions for the post on the bottom of the page. All of the other buttons toggle the information for that one post. How can I give this function a general name, but still have it interact uniquely with each post?
You shouldn't be doing this as part of the name anyway. The post id is a parameter. The only collocated part is working out how to pass it to the Django URL tag
function toggleLike(post_id){
$.ajax({
url: "{% url 'photo_blog-post_like_api' "00000" %}".replace("00000", post_id)
success: function(data) {
$("#likeCount" + post_id).html(data.like_count + ' likes');
$('#imageElement' + post.id).html(data.img);
}
});
};
</script>
<a id=imageElement{{post.id}} onclick="toggleLike({{post.id}})"><img src="/media/nav_buttons/liked.svg" height="17" width="17">
I want to add something to database using Ajax. I have a link which submits the form and then Ajax call should work, but it's not. I use this same Ajax call on different page, but in that form I'm using simple button with type submit. But on this page, I want to submit with ...
This is the form
{!! Form::open(['id' => 'ajax-form', 'style' => 'float:right']) !!}
<input type="hidden" name = "idUser" id="idUser" value="{{Auth::user()->id}}">
<input type="hidden" name = "idCampaign" id="idCampaign" value="{{$campaign->id}}">
<a class="fa fa-bookmark fa-2x" onclick="document.getElementById('ajax-form').submit();" aria-hidden="true" href="javascript:{}" style="color:#fd8809"></a>
{!! Form::close() !!}
This is the Ajax:
$("#ajax-form").submit(function(event) {
event.preventDefault();
var form = $(this);
$.ajax({
type: "post",
url: "{{ url('addFavorites') }}",
dataType: "json",
data: form.serialize(),
success: function(data){
if(data.status == 'failedd'){
swal("Error!", "You have already added this campaign to favorites! If you want to remove it, go to your Favorites list page", "error")
}
else{
swal("Success!", "You added the campaign "+ data.idCampaign + " to favorites!", "success")
}
},
error: function(data){
swal("Error!", "error")
},
complete: function (data) {
}
});
});
When I click on this link, it redirects me to another page which throws: MethodNotAllowedHttpException.
Change your ajax url to this:
url: '/addFavorites',
and your route to this:
Route::post('/addFavorites', 'SearchController#addFavorites');
Just to make sure you point at the same url
EDIT:
make sure that you have one route with get and the same route with post. see bellow:
Route::get('/addFavorites', 'SearchController#loadFavorites'); <-to load the page
Route::post('/addFavorites', 'SearchController#submitFavorites'); <-to submit the data
Change this: $("#ajax-form").submit(function(event) {
To this: $('#yourid').click(function(){
Remove the onclick in the 'a' element and add the id='yourid' with the name you want.
MethodNotAllowedHttpException usually comes when you haven't defined route or you have defined route for get method and you are using the route for post method. please check your routes.php
i have a html page, which contains a form and i want when the form is successfully submited, show the below div:
<div class="response" style="display: none;">
<p>you can download ithere</p>
</div>
i also have a jquery function:
<script type="text/javascript">
$(function() {
$('#sendButton').click(function(e) {
e.preventDefault();
var temp = $("#backupSubmit").serialize();
validateForm();
$.ajax({
type: "POST",
data: temp,
url: 'backup/',
success: function(data) {
$(".response").show();
}
});
});
});
</script>
and in my views.py (code behind) i create a link and pass it to html page. i have:
def backup(request):
if request.is_ajax():
if request.method=='POST':
//create a link that user can download a file from it. (link)
variables = RequestContext(request,{'link':link})
return render_to_response('backup.html',variables)
else:
return render_to_response('backup.html')
else:
return render_to_response("show.html", {
'str': "bad Request! :(",
}, context_instance=RequestContext(request))
backup = login_required(backup)
my problem: it seems that my view doesn't execute. it doesn't show me the link that i send to this page. it seems that only jQuery function is executed. i'm confused. how can i make both of them to execute(i mean jQuery function and then the url i set in this function which make my view to be executed.)
i don't know how to use serialize function. whenever i searched, they wrote that:
The .serialize() method creates a text string in standard URL-encoded notation and produces query string like "a=1&b=2&c=3&d=4&e=5.
i don't know when i have to use it, while i can access to my form field in request.Post["field name"]. and i don't know what should be the data which is in success: function(data) in my situation.
thank very much for your help.
You have to get and display the data from your ajax post function, where data is the response you render through your DJango server, for example:
t = Template("{{ link }}")
c = Context({"link": link})
t.render(c):
Your JS / jQuery should become something like this:
<script type="text/javascript">
$(function() {
$('#sendButton').click(function(e) {
e.preventDefault();
var temp = $("#backupSubmit").serialize();
validateForm();
$.ajax({
type: "POST",
data: temp,
url: 'backup/',
success: function(data) {
// 'data' is the response from your server
// (=the link you want to generate from the server)
// Append the resulting link 'data' to your DIV '.response'
$(".response").html('<p>you can download ithere</p>');
$(".response").show();
}
});
});
});
</script>
Hope this helps.