Django Like function with ajax - python

First of all : I already checked all the related answers and questions .... they didn't help me
so I am trying to create ajax based like button with multiple users and multiple objects or posts i tried a lot but none of them works but i steel have the base
models.py:
class BlogPost(models.Model):
#some fields
class Like (models.Model):
user = models.ForeignKey(User)
post = models.ForeignKey(BlogPost)
views.py
from .models import Like
def PostLikeToggle(request):
#here i want to capture the request check if the user liked the post or
# no by sending user.username and post.title to the endpoint like.html
#and then update his status
return render(request, 'like.html')
urls.py
from plateform import views as plateform
urlpatterns = [
#other urls
url(r'^like/', plateform.PostLikeToggle, name='PostLikeToggle'),]
like.html
{% if liked == 'false' %}
false
{% elif liked == 'true' %}
true
{% endif %}
blogpost.html
#ajax
$('.thumb').click(function () {
$.ajax({
type: 'POST',
url: '/like/',
data: {
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
},
success: LikePost,
dataType: 'html'
});
function LikePost(data, jqXHR) {
console.log(data)
}
});
UPDATE
I tried to figure it out so I added some things
models:
class BlogPost(models.Model):
#some fields
liked = models.ManyToManyField(User, related_name='PostLikeToggle')
#REMOVED class Like (models.Model)
views:
def PostLikeToggle(request):
user = request.user
if request.method == 'POST':
post_id = request.POST['post_id']
post = get_object_or_404(posts, id=post_id)
_liked = user in post.liked.all()
if _liked :
post.liked.remove(user)
else:
post.liked.add(user)
return JsonResponse({'liked':_liked})
So am I on the right way ??

okey I will just post my answer .... it was easy trick but i was little bit stingy ...
In the models file i added ManytoMany field with the relation of users ( many users + many posts)
class BlogPost(models.Model):
#more fields
liked = models.ManyToManyField(User, related_name='PostLikeToggle')
in the views i created the view which it will accept the request from the blogpost views and check if user already liked the post or no ( add the user to the liked field if liked return true remove it if .... )
def PostLikeToggle(request):
user = request.user
if request.method == 'POST':
post_id = request.POST['post_id']
post = get_object_or_404(posts, id=post_id)
_liked = user in post.liked.all()
if _liked :
post.liked.remove(user)
else:
post.liked.add(user)
return JsonResponse({'liked':_liked})
this views is associated with url where we will get the response :
url(r'^like/', plateform.PostLikeToggle, name='PostLikeToggle')
and in your blog post template you will need to link Jquery and add this Ajax function
(don't forget to customize it with your own variable class , url ... )
$('.thumb').click(function () {
$.ajax({
type: 'POST',
url: {% url 'PostLikeToggle' %},
data: {
'post_id': {{ post_slug.id }},
'csrfmiddlewaretoken': $('input[name=csrfmiddlewaretoken]').val(),
},
success: LikePost,
dataType: 'html'
});
function LikePost(data, jqXHR) {
var data = $.parseJSON(data)
if (data['liked']) {
$('.thumb').removeClass("fas fa-thumbs-up").addClass('far fa-thumbs-up')
}
else
{
$('.thumb').removeClass("far fa-thumbs-up").addClass('fas fa-thumbs-up')
}
}
});
this worked for this time if there is any exception or you have better way just post it and i will mark it
NOTICE : you have to check if the user if authenticated in the template to hide the like button or redirect him to login ....

Related

How to return related value from database after click function by ajax in django?

html
<div>
{{ productform.vendorid|as_crispy_field }}<a id="vendor_id_search" class="btn btn-info">search</a></br>
<div style="display:none;" id="show_vendorname">hjkh</div><br>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$("#vendor_id_search").click(function (event) {
event.preventDefault();
var vendor_id = $("#id_vendorid").val();
$.ajax({
url: '/ajax/find_vendorname/',
method: 'GET',
data: {
'vendor_id': vendor_id
},
dataType: 'json',
success: function (data) {
$("#show_vendorname").show(data)
}
});
});
views.py
#vendor_name_find_ajax
def find_vendorname(request):
if request.is_ajax():
vendorid = request.GET.get('vendor_id', None)
username = CustomUser.objects.filter(first_name=vendorid)
return username
I want to display the related name from the database table for that vendorid after the user typed the vendorid field and once clicked the button, the related name should be displayed on that particular div. Here, I have made a mistake and don't know to get that value.
$("#show_vendorname").show(data) unhide the div, but don't set in the data.
You need set the data before with $.html()
$("#show_vendorname").html(data).show()
EDIT:
Besides, your view needs to return a HttpResponse:
from django.http import HttpResponse
def find_vendorname(request):
if request.is_ajax():
vendorid = request.GET.get('vendor_id', None)
username = CustomUser.objects.filter(first_name=vendorid)
return HttpResponse(username)

How to return relative to request django

In my django project, I built a little like-button. The problem is, that I had it only when I take a detailed view on a post, and now want to put it on the home page, where multiple posts are shown. The problem the Like Function of the button returns to the detailed page, but I want to make the return dependent from the url where the like came from, so that I can just scroll ahead on the home page or what ever page am on, without being returned to another page. So here is my views.py Like function:
def PostLike(request, pk):
post = get_object_or_404(Post, id=request.POST.get('post_id'))
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
else:
post.likes.add(request.user)
return HttpResponseRedirect(reverse('post-detail', args=[str(pk)]))
So in a nutshell: how could I change my Like function so that I am returned to the page I liked from?
Your function returns a Redirect, that's why you are redirected to the detail page.
If you want to stay on the same page after clicking 'Like' you could submit a request through Ajax and return a JsonResponse with a message or a value depending on what you get from the database query.
How to do this varies based on what JS library or framework you are using. Here is a simplistic JQuery example:
in views.py
from django.http import JsonResponse
from django.shortcuts import get_object_or_404
def like_or_unlike(request, id):
if request.user.is_authenticated:
try:
post = get_object_or_404(Post, id=id)
if post.likes.filter(id=request.user.id).exists():
post.likes.remove(request.user)
message = 'You unliked post ' + id
else:
post.likes.add(request.user)
message = 'You liked post ' + id
except:
message = 'Error processing like for post ' + id
else:
message = 'You must be logged in to like a post.'
return JsonResponse({ 'result': message })
in urls.py
from django.urls import path
from . import views
urlpatterns = [
...
path("like/<id>/", views.like_or_unlike),
]
in template.html
<button class="{% if post.liked %}color-blue{% else %}color-white{% endif %}"
id="post_{{ post.id|stringformat:"s" }}"
onclick="postLike( '{{ post.id|stringformat:"s" }}' )"> Like this post </button>
<script>
function postLike(id) {
var element = "#post_" + id
$.ajax({
url: '/like/' + id,
type: 'get',
contentType: 'application/json',
success: function(data) {
console.log(data);
if $(element).hasClass("color-white") {
$(element).removeClass("color-white");
$(element).addClass("color-blue");
} else {
$(element).removeClass("color-blue");
$(element).addClass("color-white");
}
},
error: function(jqXhr, textStatus, errorThrown) {
console.log(errorThrown);
}
});
}
</script>
I think you should use Ajax request for it so you don't even reload page. Just handle it in JavaScript.
Otherwise you can redirect base on request.referer value to go back to the view where click was made

How to remove session variable in a template after it's job is done in django

I have a app called dashboard which is where I redirect all logged in users with an option to add articles by the user.
After the user hits Submit button in the form, the data is sent to /dashboard/article/save URL via POST and after the data is stored, the view returns HttpResponseRedirect to show_dashboard which renders dashboard.html with a session variable result.
In the dashboard template file, I have added a notify.js code to show acknowledgements to user. The problem is if this session var is defined, everytime the dashboard page is showed, the notification is triggered EVEN if the user didn't add an article.
(I'm new to using web frameworks so I do not know how this all works properly)
Some code:
dashboard/models.py:
class Article(models.Model):
id = models.IntegerField(primary_key=True)
ar_title = models.CharField(max_length=25)
ar_data = models.CharField(max_length=500)
user = models.ForeignKey(User,on_delete=models.CASCADE)
def getArticleTitle(self):
return self.title
def getArticleData(self):
return self.title
def getArticleAuthor(self):
return self.user
dashboard/urls.py:
urlpatterns = [
url(r'^$', views.show_dashboard,name='home_dashboard'),
url(r'^profile/save/', views.save_profile,name="save_profile"),
url(r'^newsfeed/', views.get_newsfeed,name="newsfeed",),
url(r'^profile/', views.show_profile,name="show_profile"),
url(r'^article/save/', views.add_new_article,name="add_new_article"),
]
dashboard/views.py:
#login_required
def show_dashboard(request):
return render(request,'dashboard/dashboard.html',{'form':NewArticleForm()})
def add_new_article(request):
if(request.method == 'POST'):
ar_title= request.POST['ar_title']
ar_data = request.POST['ar_data']
user = request.user
form = NewArticleForm(request.POST)
if(form.is_valid()):
Article.objects.create(ar_title=ar_title,ar_data=ar_data,user=user)
request.session["result"] = "add_article_OK"
return HttpResponseRedirect(reverse('home_dashboard'))
dashboard.html:
{% ifequal request.session.result 'add_article_OK' %}
<script>
$.notify("New article added successfully",
{position:"bottom right","className":"success","autoHide":"yes","autoHideDelay":"3000"});
</script>
{% endifequal %}
Now, how do I remove this session value after it has displayed the message? I know del request.session['result'] can be issued but where can I put it in this heirarchy of moves?
Do it in the show_dashboard view.
Instead of getting the value from the session in the template, pop it in the view and pass it to the template; that way you take care of getting and clearing it in one go.
#login_required
def show_dashboard(request):
context = {
'form': NewArticleForm(),
'result': request.session.pop('result', None)
}
return render(request,'dashboard/dashboard.html',context)
...
{% ifequal result 'add_article_OK' %}

Requests in Django

I'm newer in Django and some time ago I've totally stuck on problems with my requests. I'm trying to do POST from Django form. I do that with json and AJAX
Here is my code
form.py
class PostForm(forms.ModelForm):
class Meta:
model = Message
fields = ['message_text']
widgets = {
'message_text': forms.TextInput(
attrs={'id': 'message_text', 'required': True,
'placeholder': 'new message...', }),}
views.py
def index(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.cleaned_data
message_t = request.POST.get('message_text')
response_data = {}
new_mess = Message(message_text = message_t,
post_time = message_t.created,
username="second")
new_mess.save()
response_data['result'] = message_t
else:
response_data['result'] = 'nothing...'
else:
form = PostForm()
template = loader.get_template('chat/index.html')
context = RequestContext(request, {
'form': form, })
return HttpResponse(template.render(context))
(In another variant of views.py I tried to separate POST request handling to another function, but it doesn't work as well)
html:
<form method="POST" id="post-form">
<td class="col-lg-6"><div class="fieldWrapper" id="the_post"
class="form-control" type="text">
{{ form.message_text }}
</div></td>
<td class="col-lg-6"> <input type="submit" value="Post"
class="btn btn-success" name = "Post"></td>
</form>
js:
$(function() {
$('#post-form').on('submit', function(event){
event.preventDefault();
console.log("form submitted!") // sanity check
create_post();
});
function create_post() {
console.log("create post is working!") // sanity check
$.ajax({
url : "/chat/new_message/", // the endpoint
type : "POST", // http method
data : { the_post : $('#post-form').val() },
success : function(json) {
$('#post-form').val(''); // remove the value from the input
console.log(json); // log the returned json to the console
console.log("success");
},
error : function(xhr,errmsg,err) {
...
}
});
};
});
In the result my POST is successful, no error appears, but no record in the base created too.
Note: Also I've excluded csrf everywere
Can someone help me to figure out what's wrong?
The form is not valid. It can never be valid, because you are sending a JSON dictionary with the form data inside the key "the_post", but you haven't told the view to look there.
And the view can't report back the status of the form, because you construct a response - "response_data" - and then ignore it.
Finally, your view does not send back JSON anyway - it sends back the rendered template, as if it were a normal non-Ajax view - so the receiving JS has no idea what to do with it.
I've found the fix for my POST.
The main problem was in json body, I was using wrong value name, it has to be:
data : { the_post : $('#message_text').val() },
Now request is not empty.

How to return django form object in an AJAX request from django template?

I am trying to call my view from django template via an Ajax call.
I want the form object in response from view such that I can render this form via jquery in a div element.
Is it possible ? How?
This is what i tried:
home.html
function get_edit_form(button, id)
{
$.ajax({
url: "/manage/licenses/{{mls_signup_code}}/{{agent_id}}/" + id + "/",
type: "get",
data: {id: id},
success: function(response) {
console.log(response);
$("#formdiv").html({{ response.as_p }});
}
})
}
Views.py
elif request.method == "GET":
owned_license_id = request.GET.get('id', '')
form = OwnedLicenseForm(owned_license_id)
return form
I see what you are trying to do, but you cannot render the html form this way:
$("#formdiv").html({{ response.as_p }});
I think you are confusing server side rendering (Django templates) with client side rendering. Server side rendering happens when your server is processing the request, it cannot render objects produced by javascript running in the browser.
Because response is a javascript object, obtained by jquery sending an Ajax request to your url. At this time, the page has already been rendered by Django's template engine, and sent to the browser. There is no way for Django template to even be aware of this response.
I understand you want to use the as_p() method to render the form, you can do it like this:
function get_edit_form(button, id)
{
$.ajax({
url: "/manage/licenses/{{mls_signup_code}}/{{agent_id}}/" + id + "/",
type: "get",
data: {id: id},
success: function(response) {
console.log(response);
// response is form in html format
$("#formdiv").html(response);
}
})
}
# Views.py
elif request.method == "GET":
owned_license_id = request.GET.get('id', '')
form = OwnedLicenseForm(owned_license_id)
return HttpResponse(form.as_p()) # return a html str
You can accomplish this with a combination of Django and JQuery.
Step 1: Create an ultra simple form_from_ajax.html Template
The template can be as simple as {{form.as_p}}. The point is to not inherit your base template. You're simply using this form_from_ajax.html template to render the HTML of the form.
Step 2: Create a View with a slug argument that helps you get the correct form
def payment_method_ajax(request, method): # method is your slug
"""Load a dynamic form based on the desired payment method"""
options = {
'ach': ECheckForm(), # Dynamic form #1
'credit-card': CreditCardForm(), # Dynamic form #2
}
if method in options.keys():
context = {'form': options[method]}
else:
context = None
template = 'your_app_name/form_from_ajax.html'
return render(request, template, context)
Step 3: Define the AJAX url in urls.py
[...
path(
'payment-method-ajax/<slug:method>/', # notice the slug in the URL
views.payment_method_ajax,
name='payment-method-ajax'),
...]
Step 4: Update your template where you'd like the AJAX loaded form to appear
Make some buttons to have the user select an approprate form option
<button id="btn_ach" onclick="load_payment_form(this)">ACH</button>
<button id="btn_credit_card" onclick="load_payment_form(this)">Credit Card</button>
form-fields is where the dynamic form will be loaded
<form id="id-form" style="display: none;">
{% csrf_token %}
<div id="form-fields"></div>
<input type="submit" value="Save Payment Details"/>
</form>
Make sure to add slugs to your main view's context
context = {
'target': 'Add a New Payment Method',
'h1': 'Add a New Payment Method',
'ach': 'Save an ACH Profile',
'credit_card': 'Save a Credit Card Profile',
'slugs': ['ach', 'credit-card'], # Here are the slugs ****
}
Step 5: Load the form with JQuery and the button's onclick
<script>
var ach = 'ACH';
var creditCard = 'Credit Card';
var form_urls ={
ach : '{% url "payment-method-ajax" slugs.0 %}',
creditCard : '{% url "payment-method-ajax" slugs.1 %}',
}
function load_payment_form(btn) {
if(btn.innerText==ach) {
get_url = form_urls['ach'];
type = ach;
}
else if(btn.innerText==creditCard) {
console.log('Load credit card form');
get_url = form_urls['creditCard'];
type = creditCard;
}
$.get({'url': get_url}).done(
function(data) {
document.getElementById('form-fields').innerHTML = data;})
document.getElementById("id-form").style.display = "block";
}
</script>

Categories