I am using Ajax with Django 1.10 to implement a like functionality ( a user likes an image posted by another user) on my website. I have the following code :
The views file :
#ajax_required
#login_required
#require_POST
def image_like(request):
image_id = request.POST.get('id')
action = request.POST.get('action')
if image_id and action:
try:
image = Image.objects.get(id=image_id)
if action == 'like':
image.users_like.add(request.user)
else:
image.users_like.remove(request.user)
return JsonResponse({'status':'ok'})
except:
pass
return JsonResponse({'status':'ko'})
def image_detail(request, id, slug):
image = get_object_or_404(Image, id=id, slug=slug)
return render(request,
'images/image/detail.html',
{'section': 'images',
'image': image})
In base.html :
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
<script src=" http://cdn.jsdelivr.net/jquery.cookie/1.4.1/jquery.cookie.min.js "></script>
<script>
var csrftoken = $.cookie('csrftoken');
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", csrftoken);
}
}
});
$(document).ready(function(){
{% block domready %}
{% endblock %}
});
</script>
And finnaly in the detail.html :
{% extends "base.html" %}
{% block title %}{{ image.title }}{% endblock %}
{% block content %}
...
{% with total_likes=image.users_like.count users_like=image.users_like.all %}
<div class="image-info">
<div>
<span class="count">
<span class="total">{{ total_likes }}</span>
like{{ total_likes|pluralize }}
</span>
<a href="#" data-id="{{ image.id }}" data-action="{% if request.user in users_like %}un{% endif %}like" class="like button">
{% if request.user not in users_like %}
Like
{% else %}
Unlike
{% endif %}
</a>
</div>
{{ image.description|linebreaks }}
</div>
<p> Image liked by :</p>
<div class="image-likes">
{% for user in image.users_like.all %}
<div>
<p>{{ user.last_name }}</p>
</div>
{% empty %}
Nobody likes this image yet.
{% endfor %}
</div>
{% endwith %}
{% endblock %}
{% block domready %}
$('a.like').click(function(e){
e.preventDefault();
$.post('{% url "images:like" %}',
{
id: $(this).data('id'),
action: $(this).data('action')
},
function(data){
if (data['status'] == 'ok')
{
var previous_action = $('a.like').data('action');
// toggle data-action
$('a.like').data('action', previous_action == 'like' ?
'unlike' : 'like');
// toggle link text
$('a.like').text(previous_action == 'like' ? 'Unlike' :
'Like');// update total likes
var previous_likes = parseInt($('span.count .total').text());
$('span.count .total').text(previous_action == 'like' ?
previous_likes + 1 : previous_likes - 1);
}
}
);
});
{% endblock %}
While I mostly understand the code itself, I need help understanding in what orders the requests, the callback functions and everything else is executed ... something like : ,users clicks the like button, that information is passed to the server , it is being manipulated, data-base modified , sent back, the page changes ...
Tell me if any extra code ( models, urls etc. ) is needed. Could't post everything.
Related
in my web site i want to show the user ratings for that i used the infinite scroll but i am facing one problem.
when it first loads the data before calling the <a class="infinite-more-link" href="?page={{ ratings.next_page_number }}"></a> it is showing the star with the count of vote,but when after calling the <a class="infinite-more-link" href="?page={{ ratings.next_page_number }}"></a> it is not showing the star.
my views.py
#login_required
def ratings_user(request,pk):
ratings = VoteUser.objects.filter(the_user_id=pk).order_by('-pk')
paginator = Paginator(ratings, 1)
page = request.GET.get('page')
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.page(paginator.num_pages)
return render(request,request.session['is_mobile']+'profile/ratings.html',{'ratings':posts})
html
{% extends 'mobile/profile/base.html' %}
{% load static %}
{% load crispy_forms_tags %}
{% load get_companion %}
{% load cache %}
{% block title %}
Ratings
{% endblock %}
{% block leftcontent %}
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet">
{% endblock %}
{% block middlecontent %}
<div class="infinite-container">
{% for i in ratings %}
<div class="infinite-item">
<div class="w3-container w3-card w3-white w3-round w3-margin">
<img src="{{ i.the_user.profile.avatar.url }}" alt="Avatar" class="w3-left w3-circle w3-margin-right" style="width:40px;height:40px;border-radius:50%;">
{% with user=i.the_user.profile %}{{ user.prenom|title|truncatewords:2 }} {{ user.nom|title|truncatewords:1 }}{% endwith %}
<br>
<span class="stars" data-rating="{{ i.vote.vote }}" data-num-stars="5" ></span>
<hr class="w3-clear">
<p>
{{ i.commentaire|linebreaksbr }}
</p>
<span class="glyphicon glyphicon-user"></span> {% with user=i.the_sender.profile %}{{ user.prenom|title|truncatewords:2 }} {{ user.nom|title|truncatewords:1 }}{% endwith %}
</div>
</div>
{% endfor %}
</div>
{% if ratings.has_next %}
<a class="infinite-more-link" href="?page={{ ratings.next_page_number }}"></a>
{% endif %}
{% endblock %}
{% block rightcontent %}
{% endblock %}
{% block js %}
<script>
var infinite = new Waypoint.Infinite({
element: $('.infinite-container')[0]
});
</script>
<script>
//ES5
$.fn.stars = function() {
return $(this).each(function() {
var rating = $(this).data("rating");
var fullStar = new Array(Math.floor(rating + 1)).join('<i class="fas fa-star"></i>');
var halfStar = ((rating%1) !== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
var noStar = new Array(Math.floor($(this).data("numStars") + 1 - rating)).join('<i class="far fa-star"></i>');
$(this).html(fullStar + halfStar + noStar);
});
}
//ES6
$.fn.stars = function() {
return $(this).each(function() {
const rating = $(this).data("rating");
const numStars = $(this).data("numStars");
const fullStar = '<i class="fas fa-star"></i>'.repeat(Math.floor(rating));
const halfStar = (rating%1!== 0) ? '<i class="fas fa-star-half-alt"></i>': '';
const noStar = '<i class="far fa-star"></i>'.repeat(Math.floor(numStars-rating));
$(this).html(`${fullStar}${halfStar}${noStar}`);
});
}
</script>
<script>
$(function(){
$('.stars').stars();
});
</script>
{% endblock %}
i have tried to put the <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.9.0/css/all.min.css" rel="stylesheet"> inside the class="infinite-item" but it does not help.what might be the reason for that ? Thanks.
It doesn't look like .stars() will look for new elements being added to the DOM. You should look for a callback function configuration option within Waypoint.Infinite that you can call .stars() on the new elements.
I want send product id to my views.
Templates
<div class="products__header--search-result">
<ul>
{% for product in products %}
<li onclick="change('{{ product.id }}')">{{ product.name }}</li>
{% endfor %}
</ul>
</div>
<script>
function change(foo) {
$.ajax({
url: {% url 'dashboard' %},
data: {
'foo': foo,
},
});
}
</script>
views.py
myRequets = request.GET.get('foo')
But myRequets return 'None'
How can I fix this?
Is there a better way to pass values to views.py?
You don't need JS to do this because Django allows parameters in urls:
# URLconf
from django.urls import path
from . import views
urlpatterns = [
path('product/', views.product),
path('product/<int:product_id>/', views.product),
]
views.py
# View (in product/views.py)
def product(request, product_id=None):
products = None
if product_id:
# Output the appropriate page of product entry, according to product_id.
return ...
# Output the appropriate page when product_id is None
return ...
Source:
https://docs.djangoproject.com/en/3.2/topics/http/urls/#example (adapted)
Then in your template:
{% if products %}
<div class="products__header--search-result">
<ul>
{% for product in products %}
<li>{{ product.name }}</li>
{% endfor %}
</ul>
</div>
{% endif %}
am using django 2.0 and am trying to make this blog, the issue is that once i click the next page the active bar in the pagination section dont change mean from 1 to 2 see pic image
i don't know where is the mistake
here is the views.py
def post_list(request):
object_list=Post.objects.filter(status='Published').order_by("-created")
pages = pagination(request,object_list,3)
context={
'items':pages[0],
'page_range':pages[1],
}
return render(request,"blog.html",context)
pagination function
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
def pagination(request,data,num=10):
paginator = Paginator(data,num) # Show 5 contacts per page
page = request.GET.get('page',5)
try:
items=paginator.page(page)
except PageNotAnInteger:
items=paginator.page(5)
except EmptyPage:
items=paginator.page(paginator.num_pages)
index=items.number=1
max_index=len(paginator.page_range)
start_index=index - 5 if index >= 5 else 0
end_index=index + 5 if index <= max_index - 5 else max_index
page_range=paginator.page_range[start_index:end_index]
return items, page_range
and pagination.html
<nav>
{% if items.has_other_pages %}
<ul class="pagination">
{% if items.has_previous %}
<li>«</li>
{% else %}
<li class="disabled"><span>«</span></li>
{% endif %}
{% for i in page_range %}
{% if items.number == i %}
<li class="active"><span>{{ i }} <span class="sr-only">(current)</span></span></li>
{% else %}
<li>{{ i }}</li>
{% endif %}
{% endfor %}
{% if items.has_next %}
<li>»</li>
{% else %}
<li class="disabled"><span>»</span></li>
</ul>
{% endif %}
{% endif %}
</nav>
blog.html
{% for obj in items %}
{% if obj.status == 'Published' %}
<article>
<img src="{{obj.thumb.url}}" alt="" />
<div class="post-content">
<h2>{{obj.title}}</h2>
{{obj.created}} Author {{obj.user}} <h4>{{obj.Category}}</h4>
<hr/>
<p>{{obj.body}}</p>
<a class="mtr-btn button-navy ripple" href= "{% url 'post_detail' obj.slug %}">Continue reading →</a><br>
</div>
</article>
{% endif %}
{% endfor %}
{% include 'pagination.html' %}
</div>
Remove the = 1 from the line index = items.number = 1
I'm trying to embed tweets using python django and javascript.
This is my views.py currently:
def tweets(request):
context_dict = {}
tweets_today = Tweet.objects.order_by('-favorites')
tweets_today = tweets_today[:15]
context_dict['tweets_today'] = tweets_today
return render(request, 'summary/tweets.html', context_dict)
And my HTML (base.html has the twitter JS script)
{% extends 'base.html' %}
{% block body_block %}
<div class="container">
{% for tweet in tweets_today %}
<div class="block social-block social-twitter">
<div id="container_{{ forloop.counter }}">
</div>
</div>
<script>
window.onload = (function () {
twttr.widgets.createTweet(
'{{ tweet.tweet_id }}',
document.getElementById('container_{{ forloop.counter }}'),
{
theme: 'dark'
}
);
});
</script>
{% endfor %}
</div>
{% endblock %}
For some reason this is only embedding one tweet. Is it because of the window.onload?
I have been working through the Tango with Django exercises to cut my teeth into Django. Almost done but having a problem with the Ajax part.
Ajax function to auto_add a page is not being called. Idk what the problem is since the other functions are being called.
On the shell prompt, there is no call to the ajax function at all. Help needed.
Pertinent code attached. It is the same as on the website link above.
static/rango-ajax.js
$('.rango-add').click(function(){
var catid = $(this).attr("data-catid");
var title = $(this).atrr("data-title");
var url = $(this).attr("data-url");
$.get('/rango/auto_add_page/', {category_id: catid, url: url, title: title}, function(data){
$('#pages').html(data);
me.hide();
});
});
templates/rango/category.html
{% if user.is_authenticated %}
<button data-catid="{{category.id}}" data-title="{{ result.title }}" data-url="{{ result.link }}" class="rango-add btn btn-mini btn-info" type="button">Add</button>
{% endif %}
rango/views.py
#login_required
def auto_add_page(request):
context = RequestContext(request)
cat_id = None
url = None
title = None
context_dict = {}
if request.method == 'GET':
cat_id = request.GET['category_id']
url = request.GET['url']
title = request.GET['title']
if cat_id:
category = Category.objects.get(id=int(cat_id))
p = Page.objects.get_or_create(category=category, title=title, url=url)
pages = Page.objects.filter(category=category).order_by('-views')
#Adds our results list to the template context under name pages.
context_dict['pages'] = pages
return render_to_response('rango/page_list.html', context_dict, context)
rango/urls.py
urlpatterns = patterns('',
url(r'^$', views.index, name='index'),
url(r'^goto/$', views.track_url, name='track_url'),
url(r'^add_category/$', views.add_category, name='add_category'),
url(r'^auto_add_page/$', views.auto_add_page, name='auto_add_page'),
Complete code is at this link.
your code is good, the only thing what you have to do is to define your template in /tango/templates/rango/page_list.html. This template have the following code:
{% if pages %}
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
And inside of your category template you must define the following code:
% if category %}
{% if user.is_authenticated %}
Add a new Page <br>
{% endif %}
{% if pages %}
<div id="pages">
<ul>
{% for page in pages %}
<li>
{{ page.title}}
{% if page.views > 1 %}
({{page.views}} views)
{% elif page.views == 1 %}
({{page.views}} view)
{% endif %}
</li>
{% endfor %}
</ul>
</div>
{% else %}
<strong> No Pages currently in category. </strong>
{% endif %}
{% else %}
The specified category {{ category_name }} does not exist!
{% endif %}
I'm working through this section of the tutorial now and just want to add to Héctor's answer. To avoid duplicating the code to display the list of pages I did the following:
I added a get_page_list() method to tango/rango/templatetags/rango_extras.py, similar to the get_category_list() method used to display a list of categories in an earlier section of the tutorial.
from rango.models import Page
#register.inclusion_tag("rango/page_list.html")
def get_page_list(category):
pages = Page.objects.filter(category=category) if category else []
return {'pages': pages}
Then we just need to load rango_extras and call the get_page_list() method in tango/templates/rango/category.html.
{% extends 'rango/base.html' %}
{% load rango_extras %}
<!-- Existing code -->
{% if category %}
<!-- Existing code to show category likes and like button -->
<div id="page_list">
{% get_page_list category %}
</div>
<!-- Existing code to show search if user is authenticated -->
{% else %]
The specified category {{ category_name }} does not exist!
{% endif %}
This allows you to display the list of pages when a category page is first loaded and then refresh it if a category is added from the search area, without having to duplicate any code.