How to save a wish icon checked after page refresh -Django - django

Trying to keep selected icon in product cards active after page refresh
when the user refresh the page I want that the icon to remain a full heart and not an empty heart. How could I do that?
views.py
#login_required
def add_wishlist (request):
if request.is_ajax() and request.POST and 'attr_id' in request.POST:
if request.user.is_authenticated:
data = Wishlist.objects.filter(customer = request.user,product_id= int(request.POST['attr_id']))
if data.exists():
data.delete()
else:
Wishlist.objects.create(customer= request.user,product_id = request.POST['attr_id'])
else:
print("No Product is Found")
return redirect("products:product_all")
product_all.html
<div id='alCarrito' class="like-container">
{% if product in wishlisted_list %}
<span class="like heart " id="id" attr_id="{{product.id}}" action_url="{% url 'products:add_wishlist' %}">
<i class="fas fa-heart"></i> </span>
{% else %}
<span class="like" id="id" attr_id="{{product.id}}" action_url="{% url 'products:add_wishlist' %}"><i class="far fa-heart"></i></span>
{% endif %}
</div>
wishlist.js
$(document).ready(function(){
$(".like").click(function(){
var attr_id = $(this).attr('attr_id')
var action_url = $(this).attr('action_url')
var that = $(this)
$.ajax({
url: action_url,
type: "POST",
data: {'attr_id': attr_id },
headers: { "X-CSRFToken": $.cookie("csrftoken") },
success: function (response) {
console.log("Success")
that.toggleClass("heart");
},
});
});
});

Related

Pagination Ajax Django

I get the data through the search and display it on the page, since there is a lot of data, I want to implement pagination via Ajax. But when you click on the pagination, everything disappears and the data is not updated. If Ajax is turned off, then everything works, but there is a transition to the page (search/?page=2), which immediately removes all search results.
Please help, what am I doing wrong?
def search_venus(request):
if request.method == "GET":
searched = request.GET.get('searched', False)
p = Paginator(Movie.objects.filter(title__contains=searched), 1)
page = request.GET.get('page')
object_list = p.get_page(page)
coursesearch = Course.objects.filter(name__contains=searched)
context = {
'searched':searched,
'object_list':object_list,
'coursesearch':coursesearch,
}
return render(request, 'search.html', context)
Ajax
function ajaxPagination_s_m() {
$('#pagination_s_movie a.page-link').each((index, el) => {
$(el).click((e) => {
e.preventDefault()
let page_url = $(el).attr('href')
console.log(page_url)
$.ajax({
url: page_url,
type: 'GET',
csrfmiddlewaretoken: '{{ csrf_token }}',
success: (data) => {
$('#search_movie').empty()
$('#search_movie').append($(data).find('#search_movie').html())
$('#pagination_s_movie').empty()
$('#pagination_s_movie').append($(data).filter('#pagination_s_movie').html())
}
})
})
})
Form search
<div class="form_search">
<form action="{% url 'search-venus' %}" method=GET>
{% csrf_token %}
<input class="inp_text" name="searched" type="search" placeholder="Схемы, видео, книги">
<button type="submit"></button>
</form>
</div>

Django - Submit multiple forms using ajax

I would like to understand how to submit 2 forms simultaneously using ajax.
I display a form composed of 2 model forms, for 2 models linked with OneToOne relationship. Managing the display is not a big deal, I can also manage the submit using a Django view; but I would like to know how to deal with javascript.
Why? The form is called from a global menu and displayed in a modal, and I would like only to close the modal on submit, but not refresh the page.
Here are some (simplified) code snippets I tried so far:
user_profile.html (modal form):
<form id="upd-user" action="." method="post" url-endpoint="{% url 'polls:upd_user_detail' %}"
comp-slug="{{ comp_slug }}" usr-id="{% if usr_id %} {{ usr_id }} {% else %} 0 {% endif %}">
{% csrf_token %}
{{ user_form }}
{{ usercomp_form }}
<button class="btn btn-success" type="submit">{% if usr_id %}Mettre à jour{% else %}Créer{% endif %}</button>
&nbsp &nbsp &nbsp
<a class="btn btn-secondary back_btn" data-dismiss="modal">Annuler</a>
</form>
The modal is embedded in this snippet:
<div id="usr_detail" class="modal fade hide" role="dialog" tabindex='-1'>
<div class="modal-dialog modal-lg">
<div class="modal-content usr_form_content">
{% include './user_profile.html' %}
</div>
</div>
</div>
Javascript submit function:
$(".usr_form_content").on("submit", "#upd-user", function(event) {
event.preventDefault();
$.ajax({
method: 'POST',
url: $(this).attr('url-endpoint'),
data: {
comp_slug: $(this).attr('comp-slug'),
usr_id: $(this).attr('usr-id'),
user_form: user_form.serialize(),
usercomp_form: usercomp_form.serialize()
},
success: handleSuccess,
error: handleError,
});
function handleSuccess(data) {
$("#usr_detail").modal("hide");
};
function handleError(jqXHR, textStatus, errorThrown){
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
}
})
The error message is quite clear:
Uncaught ReferenceError: user_form is not defined
I now I need to make the transition between the form and js, I probably need to link these values to $('this) but I don't know how.
If it helps, here's the GET view:
comp_slug = request.GET["comp_slug"]
company = Company.get_company(comp_slug)
usr_id = int(request.GET["usr_id"]) # comes as string when 0
if usr_id > 0:
profile_user = User.objects.get(pk=usr_id)
user_form = UserBaseForm(instance=profile_user)
usercomp_form = UserCompForm(instance=profile_user.usercomp)
user_form.fields['username'].disabled = True # Disable updates of the field
else:
user_form = UserBaseForm()
usercomp_form = UserCompForm()
context = {
"comp_slug": comp_slug,
"company": company,
"usr_id": usr_id,
"user_form": user_form,
"usercomp_form": usercomp_form,
}
template = render_to_string('polls/user_profile.html', context=context, request=request)
return JsonResponse({"user_template": template})
And related js part (it works fine - I tried to generated necessary variables at this stage, but it did not work neither)
$('.update-user').click(function() {
$.ajax({
method: 'GET',
url: $(this).attr('url-endpoint'),
data: {
comp_slug: $(this).attr('comp-slug'),
usr_id: $(this).attr('usr-id'),
},
success: handleSuccess,
error: handleError,
});
function handleSuccess(data) {
$(".usr_form_content").html(data.user_template);
};
function handleError(error_data) {
console.log("error");
console.log(error_data);
};
})

Can not get comment id with AJAX in django

I'm fighting with this problem during several days and can not find the solution for my case. I'm trying to make system of likes without refreshing the page. In synchronous mode system of likes and dislikes works fine, but when I'm trying to add AJAX, I'm getting 405 and only one last comment is working for one click, I understand problem that Ajax doesn't understand django urls with id or pk like my variant {% url 'store:like' comment.pk %} , but how it can be solved?
There is this part from the template:
{% for comment in comments %}
<h6 class="card-header">
{{ comment.author }}<small> добавлен {{ comment.created_at|date:'M d, Y H:i' }} </small>
</h6>
<div class="card-body">
<h4>{{ comment }}</h4>
<form id="like-{{comment.pk}}" method="POST" action="{% url 'store:add_like' comment.pk %}">
{% csrf_token %}
<button style="background-color: transparent; border: none; box-shadow: none;" type="submit">
<a class="btn btn-success" id="like-count-{{comment.pk}}"> Likes {{ comment.likes.all.count }}</a>
</button>
</form>
</div>
{% empty %}
<p>Для данного товара ещё нет комментариев.</p>
{% endfor %}
my ajax call in the same template:
<script type="text/javascript">
$(document).ready(function(){
$('[id^="like-"]').submit(function(e){
e.preventDefault();
var endpoint = $(this).attr('action');
var serializedData = $(this).serializeArray();
$.ajax({
type: 'POST',
url: endpoint,
data: serializedData,
success: function(response) {
$( "#like-count-"+response["id"].toString()).text("Likes "+response["like_count"]);
},
error: function(rs, e) {
alert(rs.responseText);
}
});
})
This part from urls:
path('products/<int:pk>/like/', addlike, name='like'),
View for like:
#api_view(['POST'])
def addlike(request, pk, *args, **kwargs):
is_ajax = request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
if request.method == 'POST' and is_ajax:
post = Comment.objects.get(pk=pk)
is_dislike = False
for dislike in post.dislikes.all():
if dislike == request.user:
is_dislike = True
break
if is_dislike:
post.dislikes.remove(request.user)
is_like = False
for like in post.likes.all():
if like == request.user:
is_like = True
break
if not is_like:
post.likes.add(request.user)
if is_like:
post.likes.remove(request.user)
all_post_likes = post.total_likes() (function from models)
return JsonResponse({"success": True, "like_count": all_post_likes, "id": pk}, status=200)
else:
return JsonResponse({"success": False}, status=400)
How to force AJAX to call in pk what I need? (Finally I found the solution, updated the final version of the code)
Remove the ‍data-url‍ and set the action attribute because when you click the submit button, by default this POST request will be sent to the current URL and you will receive the 405 status code, but if you set action this POST request will be sent to the like url:
<form id="like" method="POST" action="{% url 'store:like' comment.pk %}">
{% csrf_token %}
<input type="hidden" value="{{comment.pk}}" name="id">
<input type="hidden" name="next" value="{{ request.path }}">
<button style="background-color: transparent; border: none; box-shadow: none;" type="submit">
<a class="btn btn-success" id="like"> Likes {{ comment.likes.all.count }}</a>
</button>
</form>
And in js you can get the URL like this
var endpoint = $(this).attr('action');
Update
All forms have the same "ID" and therefore only the first one is executed and the rest of the forms are not managed by Ajax, to solve this problem you can give different ID to the forms(This condition also applies to a tags):
<form id="like-{{comment.pk}}" method="POST" action="{% url 'store:like' comment.pk %}">
{% csrf_token %}
........
.....
<a class="btn btn-success" id="likes-count-{{comment.pk}}"> Likes {{ comment.likes.all.count }}</a>
And you can receive events this way and update the number of likes.
$(document).ready(function(){
$('[id^="like-"]').submit(function(e){
e.preventDefault();
var endpoint = $(this).attr('action');
var serializedData = $(this).serializeArray();
$.ajax({
url: endpoint,
method: "POST",
data: serializedData,
success: function(response){
$("#likes-count-" + serializedData[1].value).text("Likes "+response["like_count"]);
}
});
})
});
in the view you should return the new number of the likes :
return JsonResponse({"success": True, "like_count": new_like_count}, status=200)
And in the success function you can access to the new number by the response and now we change the text value of a tag to change the like count number.
^= means: selects elements that have the specified attribute with a
value beginning exactly with a given string. attributeStartsWith1
I think you should send the csrf_token with the ajax request add
headers: { "X-CSRFToken": token } to your ajax request, "token is the csrf_token" or add #csrf_exempt decorator to your function but it will keep your view unsafe against CSRF attacks.
you can find more info here https://docs.djangoproject.com/en/4.0/ref/csrf/

On submitting the Form how to read file upload control data in view coming from ajax

When I submit the form I don't want page to be reload that's why I use ajax and get data on form submission to ajax and ajax will send request to corresponding view . but I am unable to find code for file upload control in view. I am unable to get data from:
myfile = request.FILES['myfile']
myfile =request.FILES['myfile'].read()
but i am always getting error :
if request.method == 'POST' and request.FILES['filename'] raise
MultiValueDictKeyError(key)
django.utils.datastructures.MultiValueDictKeyError: 'filename'
this is my form :
$(document).ready(function(evt){
$(document).on('submit','#myform',function(e){
e.preventDefault();
var thisForm=$(this).serialize();
var action=$(this).attr('action');
var method=$(this).attr('method');
var formData = new FormData($('#myform')[0]);
console.log(formData);
$.ajax({
url: action,
type: method,
data: formData,
success: function (data) {
alert(data)
},
cache: false,
enctype: 'multipart/form-data',
processData: false
});
});
});
<form action="{% url 'process_file' %}" method="post" enctype="multipart/form-data" id="myform">
{% csrf_token %}
<div class="col-md-3 col-sm-3 firstblock padMin">
<h3>Input Data</h3>
<ul>
<li><input type="file" name="files[]" required accept=".csv" id="file_data" ></li>
<li class="checkboxIn">
<input type="checkbox" name="id" id="id" />
</li>
<li>
<input type="number" name="train_fraction" id="train_fraction" required value={% if post_data %} {{fiction}} {% else %} 0.7 {% endif %} min="0.1" step="0.1" >
</li>
</ul>
</div>
<button class="btn btn-primary btn-lg custom-process" type="submit">Process</button>
and there are other control also
</form>
Here is my view function in Python:
#csrf_exempt
def process_file(request):
#From submit action
if request.method == 'POST' and request.FILES['filename']:
print (request.POST)
id = '0' if request.POST.get('id',False)==False else '1'
res = '1' if 'res' in request.POST and request.POST['res']=='on' else '0'
ae_res = '1' if 'ae_res' in request.POST and request.POST['ae_res'] == 'on' else '0'
event_handling = '1' if 'event_handling' in request.POST and request.POST['event_handling'] == 'on' else '0'
threshold = request.POST['threshold'] if 'threshold' in request.POST else '1.0'
samplerate = request.POST['samplerate'] if 'samplerate' in request.POST else '0.1'
# myfile = request.FILES['myfile']
# myfile =request.FILES['myfile'].read()
#default action
return render(request, 'process_file.html',{})
how to read file control data in view and I am always getting an error saying 500 error whenever I open a console in the browser
request.FILES['filename'] should be request.FILES.getlist('files[]')
https://docs.djangoproject.com/en/2.2/ref/request-response/#django.http.QueryDict.getlist

Using the same method but get different result

I use {extends 'xxx.html'} to make all templates have the same 'head' and 'tail', there's an user avatar area {{ avatar }} in head, but I use the same method to pass this avatar in every views, my index.html can't correctly show the avatar, but the other can, so I assume is something wrong with my index views.
Here's the index view:
def index(request):
if request.method == 'GET':
all_user = UserInfo.objects.all()
user = all_user.filter(username=request.user.username)
return render(request, 'index.html', {
"icon": user.icon,
"user": user.username,
})
And here's a part of views which could correctly show the avatar:
if request.user.is_authenticated():
my_fav = UserFavorite.objects.all()
my_fav_num = my_fav.filter(user=request.user).count()
my_posts_num = all_posts.filter(user=request.user).count()
my_msg = UserMessage.objects.all()
my_msg_num = my_msg.filter(user=request.user, has_read=False).count()
all_user = UserInfo.objects.all()
user = all_user.get(username=request.user.username)
return render(request, 'community.html', {
"all_posts": posts,
"post_num": post_num,
"animal_kind": animal_kind,
"post_kind": post_kind,
"sort": sort,
"my_fav_num": my_fav_num,
"my_posts_num": my_posts_num,
"my_msg_num": my_msg_num,
"icon": user.icon,
"user": user.username,
})
else:
my_fav_num = 0
my_msg_num = 0
my_posts_num = 0
return render(request, 'community.html', {
"all_posts": posts,
"post_num": post_num,
"animal_kind": animal_kind,
"post_kind": post_kind,
"sort": sort,
"my_fav_num": my_fav_num,
"my_posts_num": my_posts_num,
"my_msg_num": my_msg_num,
})
HTML code:
<div class="head_bar" style="z-index: 1;">
<a class="logo" href="{% url 'index' %}">Nostray</a>
<div class="nav_bar">
<a class="nav" href="{% url 'adopt:market' %}"><span class="roll" id="adopt">领养</span></a>
<a class="nav" href="{% url 'community:allpost' %}"><span class="roll" id="community">社区</span></a>
<a class="nav" href=""><span class="roll" id="charity">公益</span></a>
</div>
{% if request.user.is_authenticated %}
<div class="current_user"><a href="">
<img src="{{ MEDIA_URL }}{{ icon }}" title="登录状态:{{ user }}" class="curr_icon">
</a></div>
{% else %}
<button class="bar_btn1" onclick="location.href={% url 'login' %}">登录</button>
<button class="bar_btn2" onclick="location.href={% url 'registe' %}">注册</button>
{% endif %}
can't see why the index can't find the avatar.
In your index you have list of user but in you 'correctly show' user is single object and it has the attrs, you need replace
user = all_user.filter(username=request.user.username)
on
user = all_user.get(username=request.user.username)
# ^^^^