How to use Ajax in Django for like button - python

I want to Ajax feature for the like button in my blog. I have implemented like feature first, it was working as expected(reloads page after clicking like button). Then, i want to implement Ajax so the page should not reload after clicking like button. But, it is not working as expected.
views.py:
def like_post(request):
user = request.user
if request.method == 'POST':
post_id = request.POST.get('id')
post_obj = get_object_or_404(Post, id=post_id)
if user in post_obj.liked.all():
post_obj.liked.remove(user)
else:
post_obj.liked.add(user)
like, created = Like.objects.get_or_create(user=user, post_id=post_id)
if not created:
if like.value == 'Like':
like.value = 'Unlike'
else:
like.value = 'Like'
like.save()
if request.is_ajax():
post = Post.objects.all()
context={
'post': post
}
html = render_to_string('blog/like_section.html', context, request=request)
return JsonResponse({'form': html})
Jquery in base.html:
<script src="https://code.jquery.com/jquery-3.1.1.min.js">
<script type="text/javascript">
$(document).ready(function(event){
$(document).on('click', '#like', function(event){
event.preventDefault();
console.log("hello")
var pk = $(this).attr('value');
$.ajax({
type : 'POST',
url : {% url 'like-post' %},
data : {'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);
},
});
});
});
</script>
like_section.html:
<form action="{% url 'like-post' %}" method="POST">
{% csrf_token %}
<input type="hidden" name="post_id" value="{{ post.id }}">
{% if user not in post.liked.all %}
<button id="like" class="btn btn-outline-info mb-4" type="submit">Like</button>
{% else %}
<button id="like" class="btn btn-info mb-4" type="submit">Unlike</button>
{% endif %}
</form>
urls.py:
path('likes/', views.like_post, name='like-post'),
It returns 404 with No Post matches the given query. My observation is, it looks it is not detecting Jquery part because if I replace 'id' with 'post_id' in request.POST.get('id') & return redirect under request.method == 'POST', it works like my previous version(Reloads page if I hit like button). So the control never goes into request.is_ajax() loop, How do I make Django to use Ajax?

Related

Ajax form not sending data in django

I am trying to send data to Django without page refresh. So I am using ajax.
Created a Django model and form
class MyModel(models.Model):
text=models.CharField(max_length=100)
class MyForm(forms.ModelForm):
class Meta:
model=MyModel
fields = "__all__"
Then send the form to the HTML page via views.py
def home(request):
print(request.POST.get('text',False))
form = MyForm(request.POST)
if request.method=='POST':
print(request.POST.get('text',False))
if form.is_valid():
data=form.save()
return render(request,'home.html',{'form':form})
Create a form in HTML template
<form action = "" id="post-form" method = "post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit" id="submit-button">
</form>
This is the javascript file
$(document).on('submit','#post-form',
function(x){
x.preventDefault();
console.log("button clicked")
$.ajax({
type:'POST',
url:'/',
data:{
text:$("id_text").val(),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val()
},
success:function(){
alert('Saved');
}
})
}
)
I think it might be the issue with URL, if i set url like this way
url:'{% url "home" %}',
Then in console, i got this error
XHR POST http://127.0.0.1:8000/%7B%%20url%20%22home%22%20%%7D
I am unable to find, where is the issue.
You should use # for selecting id, so use text:$("#id_text").val().
For using dynamic url, use like this:
url:"{% url 'home' %}",
For more information, about using dynamic urls refer this question.
Edit:
One way to use dynamic url is to pass it with onsubmit event, so try this:
Template file or home.html
<form id="post-form" method="POST" onsubmit="checking('{% url 'home' %}')">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="submit" id="submit-button">
</form>
Js file:
function checking(dynamicUrl) {
$(document).on("submit", "#post-form", function (x) {
x.preventDefault();
console.log("button clicked");
$.ajax({
type: "POST",
url: dynamicUrl,
data: {
text: $("#id_text").val(),
csrfmiddlewaretoken: $("input[name=csrfmiddlewaretoken]").val(),
},
success: function () {
alert("Saved");
},
});
});
}

Deleting a value from database based on data coming sent from a form - Django

I am trying to implement newsletter/email subscription for my project.
I created a model which only stores the email and the timestamp and uses SendGrid to send emails to the users who subscribed.
I want to include an unsubscribe button inside the emails I send them. When the user clicks unsubscribe link in the mail it appends the id of the value in db to the url and redirects to cancelsub.html where I am accessing it.
In cancelsub.html I have a form with a submit button which when a user clicks should delete the value from db. It is not working for some reason.
Models.py--
class NewsletterUser(models.Model):
email = models.EmailField(null=True)
date_added = models.DateTimeField(default=datetime.now)
def __str__(self):
return self.email
Views.py--
def NewsLetter(request):
if request.method == 'POST':
email_input = request.POST.get('email_value')
new = NewsletterUser(email=email_input)
new.save()
sendEmail(email_input)
return render(request,"pages/index.html")
def DeleteNewsLetter(request):
if request.method == 'POST':
del_id = request.POST.get('id_value')
NewsletterUser.objects.filter(id= del_id).delete()
return render(request, "newsletter/CancelSubscription.html")
cancelsub.html--
<form id="cancel-subscription-form" method="POST">
{% csrf_token %}
<div class="email-and-btn">
<button class="btn btn-danger mb-2 art-digest-btn" id="cancel-btn" type="submit" value="">Yes, Cancel It</button>
</div>
</form>
<script src="https://code.jquery.com/jquery-1.9.1.js"></script>
<script>
var current_url = window.location.href
var id = current_url.split('?')[1]
id_int = parseInt(id)
$("#cancel-btn").val(id_int);
$(document).on('submit','#cancel-subscription-form',function(e){
e.preventDefault();
$.ajax({
type:'POST',
url:'{% url "DeleteNewsLetter" %}',
data:
{
id_value: parseInt($("#cancel-btn").val()),
csrfmiddlewaretoken:$('input[name=csrfmiddlewaretoken]').val(),
},
success:function(){
}
})
});
</script>
</div>
urls.py--
urlpatterns = [
path('', views.NewsLetter, name='NewsLetter'),
path('CancelSubscription', views.CancelSubscription, name='CancelSubscription'),
path('', views.DeleteNewsLetter, name='DeleteNewsLetter'),
]
When I execute this code out, instead of deleting the value from database, it adds a blank value into the db. I'm confused as to why this is happening.
It'd be really helpful if anyone guide me where I went wrong!.
Thanks in advance!!
I understand that the URL that you send on the email is something like this: http://mywebsite.com/unsubscribe/?9
So you get the "9" with the javascript code. You don't need the javascript if you give a name to your value like this: http://mywebsite.com/unsubscribe/?user_id=9
Now, you can just doing this:
<form id="cancel-subscription-form" method="POST" action="{% url "DeleteNewsLetter" %}">
{% csrf_token %}
<div class="email-and-btn">
<button name="id_value" class="btn btn-danger mb-2 art-digest-btn" id="cancel-btn" type="submit" value="{{request.GET.user_id}}">Yes, Cancel It</button>
</div>
</form>
I think that your problem is in the javascript code, so simplify and deleting it probably your system works.

Ajax to submit a like button leading to Page 404 Error

I am trying to use Ajax to submit a like button, I believe everything is in order but I keep getting PAge 404 error after submitting the like button,
I am not sure what is the reason. Need help to identify the error.
I have made some amendments to the URL path moving it from app urls.py to the main project urls.py but the error showing now is
LikeView() missing 1 required positional argument: 'pk'
Here is the view
class PostDetailView(DetailView):
model = Post
template_name = "post_detail.html"
def get_context_data(self, *args, **kwargs):
context = super(PostDetailView, self).get_context_data()
stuff = get_object_or_404(Post, id=self.kwargs['pk'])
total_likes = stuff.total_likes()
liked = False
if stuff.likes.filter(id=self.request.user.id).exists():
liked = True
context["total_likes"] = total_likes
context["liked"] = liked
return context
def LikeView(request, pk):
# post = get_object_or_404(Post, id=request.POST.get('post_id'))
post = get_object_or_404(Post, id=request.POST.get('id'))
like = False
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
like = False
else:
post.likes.add(request.user)
like = True
context["total_likes"] = total_likes
context["liked"] = liked
if request.is_ajax:
html = render_to_string('like_section.html', context, request=request)
return JsonResponse({'form': html})
Here is the url.py in the main project, I have moved it from the app called Score the main 'url.py'
urlpatterns = [
path('like/', views.LikeView, name='like_post'),
here is the updated template
<form class="mt-0" action="{% url 'like_post' %}" method='POST'>
{% csrf_token %}
<strong> Likes
: {{total_likes}} </strong>
{% if user.is_authenticated %}
{% if liked %}
<button id='like' type='submit' name='post_id' class= "btn btn-danger btn-sm" value="{{post.id}}"> Unlike </button>
{% else %}
<button id='like' type='submit' name='post_id' class= "btn btn-primary btn-sm" value="{{post.id}}"> Like </button>
{% endif %}
{% else %}
<p><small> Login to Like </small></p>
{% endif %}
</form>
here is the ajax
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
$(document).ready(function(event){
$(document).on('click','#like', function(event){
event.preventDefault();
$var pk= $(this).attr('value');
$.ajax({
type:'POST',
url:'{% url "like_post" %}',
data:{'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);
},
});
});
});
</script>
Thank you
As error indicates, ListView class requires a positional argument which is pk. So your view class should change.
def LikeView(request):
Use this code as ListView definition.

How do I submit a form without page reload using Ajax

I'm learning Ajax on how I can submit a comment form without page reload. I'm using Django, I have list of posts in homepage each with comment form. When I submit a comment it is not saving in database and also it doesn't display in browser. When I check on Chrome console, I got an error 2 elements with non-unique id.
from django.http import JsonResponse
from django.template.loader import render_to_string
def home(request):
all_images = Post.objects.filter(poster_profile=request.user)
if request.method == 'POST':
post_id = request.POST.get("post_comment")
post_obj = Post.objects.get(pk=post_id)
form = CommentForm(request.POST)
if form.is_valid():
comment=form.save(commit=False)
comment.user=request.user
comment.commented_image=post_obj
comment.save()
else:
form=CommentForm()
context = {'all_images':all_images, 'form':form}
if request.is_ajax():
html=render_to_string('ajax_feeds_comment.html', context, request=request)
return render(request, 'home.html', context)
#home.html
{% for post in all_images %}
<img src="{{ post.image.url }}">
{% for comment in post.comments.all %}
<p>{{ comment.comment_post }}</p>
{% endfor %}
<div class="reload-form">
{% include "ajax_feeds_comments.html" %}
</div>
{% endfor %}
#ajax_feeds_comments.html
<form method="POST" class="feeds-comment" action=".">
{% csrf_token %}
<input type="hidden" value="{{post.id}}" name="post_comment">
<textarea name="comment_post" class="form-control" id="id_comment_post{{post.id}}"></textarea>
<button type="submit" class="btn btn-primary">submit</button>
</form>
<script>
$(document).on('submit', '.feeds-comment', function(event){
event.preventDefault();
console.log($(this).serialize());
$.ajax({
type: 'POST',
url: $(this).attr('action'),
data: $(this).serialize(),
dataType: 'json',
success: function(response){
$('.reload-form').html(response['form']);
},
error: function(rs, e) {
console.log(rs,responseText);
},
});
});
</script>
There are multiple things not correct here:
In your "urls.py" you should not send every request to your views. This is where you get the "favico.ico" error 500 get from. Having no favico is ok, but getting a Error 500 is not.
Check the html code for duplicate id's! These have to be unique.
If you use django variables for html, do it like this: Instead of "{{post.id}}" use: "{{ post.id }}" with spaces around the var.
In the
document.on("submit", "feeds-comment", function(){...})
you're not using the id of that element but it's class name.
Check where the submit is going to. Check Django if the request is being handled. (You see that in the console where Django is running). Also maybe Post a screenshot here!

AJAX POST Flask WTForm without refreshing the page

Good day, I have a simple web page with an email form in it. I'm trying to collect the data from it and populate a database without refreshing the template. Here is my code so far:
Form:
from flask_wtf import Form
class EmailForm(Form):
email = StringField('Email Address', [
DataRequired(message='Required field'),
Email(message='Please provide a valid email address')
])
submit = SubmitField('send')
Route:
#app.route('/', methods=('GET', 'POST'))
def index():
form = EmailForm(request.form)
if request.method == 'POST' and form.validate_on_submit():
try:
email = Email(form.data['email'])
db.session.add(email)
db.session.commit()
except IntegrityError as e:
app.logger.info(e)
return redirect(url_for('index'))
return render_template('index.html', form=form)
Ajax:
$(function() {
$('#email_submit').bind('click', function() {
$.getJSON('/', {
email: $('input[name="email"]').val()
});
return false;
});
});
Template:
<form name="collectEmail" id="collectForm" method="post" action="{{ url_for('index') }}">
{{ form.hidden_tag() }}
{{ form.csrf_token }}
{% if form.csrf_token.errors %}
<div class="warning">You have submitted an invalid CSRF token</div>
{% endif %}
<div class="input-group">
{{ form.email(class='form-control', placeholder='Your Email *', type='email')}}
<p class="help-block text-danger"></p>
<span class="input-group-btn">
{{ form.submit(class='btn btn-primary', id='email_submit', type='submit') }}
</span>
</div>
</form>
The database successfully populates; but, I would like to avoid refreshing the page after submitting the form.
You are not sending the request with AJAX, #email_submit is an input of type submit, not a button, so if you don't use preventDefault() you end up executing the default behaviour of that input.
You have 2 options there, one is using preventDefault() and the other is to switch that input to a button, so it won't submit the form before the javascript code runs.

Categories