I have a problem. I made likes to the posts on the video from YouTube. It is possible to like a post only from post_detail view and it's works correctly! How to make it possible to like posts in the post_list (in my case it's 'feed')? Please help!
MY CODE:
utils.py
def is_ajax(request):
return request.META.get('HTTP_X_REQUESTED_WITH') == 'XMLHttpRequest'
views.py
from .utils import is_ajax
def feed(request):
comments = Comment.objects.all()
posts = Post.objects.all().order_by('-created_at')
return render(request, 'main/feed.html', {'posts': posts,
'comments': comments})
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
comments = Comment.objects.filter(post=post, reply=None).order_by('-created_at')
is_voted = False
if post.votes.filter(id=request.user.id).exists():
is_voted = True
if request.method == 'POST':
comment_form = CommentForm(request.POST or None)
if comment_form.is_valid():
content = request.POST.get('content')
reply_id = request.POST.get('comment_id')
comment_qs = None
if reply_id:
comment_qs = Comment.objects.get(id=reply_id)
comment = Comment.objects.create(
post = post,
author = request.user,
content = content,
reply = comment_qs
)
comment.save()
return redirect(post.get_absolute_url())
else:
for error in list(comment_form.errors.items()):
messages.error(request, error)
else:
comment_form = CommentForm()
return render(request, 'main/post_detail.html', {'post':post,
'comment_form':comment_form,
'comments':comments,
'is_voted':is_voted})
#login_required
def post_vote(request, slug):
post = get_object_or_404(Post, id=request.POST.get('id'), slug=slug)
is_voted = False
if post.votes.filter(id=request.user.id).exists():
post.votes.remove(request.user)
is_voted = False
else:
post.votes.add(request.user)
is_voted = True
context = {
'post': post,
'is_voted': is_voted,
}
if is_ajax(request):
html = render_to_string('main/votes.html', context, request)
return JsonResponse({'form':html})
votes.html
<form action="{% url 'main:post-vote' slug=post.slug %}" method="post">
{% csrf_token %}
{% if is_voted %}
<button type="submit" id="vote" name="post_id" value="{{ post.id }}" btn="btn btn-outline">Unvote</button>
{% else %}
<button type="submit" id="vote" name="post_id" value="{{ post.id }}" btn="btn btn-outline">Vote</button>
{% endif %}
</form>
{{post.votes_count}}
post_detail.html
<div id="vote-section">
{% include 'main/votes.html' %}
</div>
<script>
$(document).ready(function(event){
$(document).on('click','#vote', function(event){
event.preventDefault();
var pk = $(this).attr('value');
$.ajax({
type: 'POST',
url: "{% url 'main:post-vote' slug=post.slug %}",
data: {'id':pk, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
dataType: 'json',
success: function(resoponse){
$('#vote-section').html(resoponse['form'])
console.log($('#vote-section').html(resoponse['form']));
},
error: function(rs, e){
console.log(rs.responseText);
}
})
});
});
</script>
feed.html
...
{% for post in posts %}
<div id="vote-section">
{% include 'main/votes.html' %}
</div>
...
{% endfor %}
<script>
$(document).ready(function(event){
$(document).on('click','#vote', function(event){
event.preventDefault();
var pk = $(this).attr('value');
$.ajax({
type: 'POST',
url: "{% url 'main:post-vote' slug=post.slug %}",
data: {'id':pk, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
dataType: 'json',
success: function(resoponse){
$('#vote-section').html(resoponse['form'])
console.log($('#vote-section').html(resoponse['form']));
},
error: function(rs, e){
console.log(rs.responseText);
}
})
});
});
</script>
models.py
class Post(models.Model):
...
votes = models.ManyToManyField(get_user_model(), related_name='votes', blank=True)
#property
def votes_count(self):
return self.votes.count()
urls.py
urlpatterns = [
path('', views.feed, name='feed'),
path('post_create/', views.post_create, name='post-create'),
path('post/<slug>/', views.post_detail, name='post-detail'),
path('post/<slug>/delete', views.post_delete, name='post-delete'),
path('post/<slug>/update', views.post_update, name='post-update'),
path('post/<slug>/vote', views.post_vote, name='post-vote'),
path('comment/<slug>/delete', views.comment_delete, name='comment-delete'),
path('comment/<slug>/update', views.comment_update, name='comment-update'),
path('comment_reply/<slug>/delete', views.reply_comment_delete, name='comment-reply-delete')
]
I understand that I need to do the same as in post detail. I tried to do this, but i got errors
def post_detail(request, slug):
post = get_object_or_404(Post, slug=slug)
comments = Comment.objects.filter(post=post, reply=None).order_by('-created_at')
is_voted = False
if post.votes.filter(id=request.user.id).exists():
is_voted = True
...
Tried to do:
def feed(request, slug=None):
comments = Comment.objects.all()
posts = Post.objects.all().order_by('-created_at')
v_post = get_object_or_404(Post, slug=slug)
is_voted = False
if v_post.votes.filter(id=request.user.id).exists():
is_voted = True
return render(request, 'main/feed.html', {'posts': posts,
'comments': comments,
'is_voted': is_voted})
got
Page not found (404)
Also tried
def feed(request, slug):
comments = Comment.objects.all()
count_filter = Q(votes=request.user)
vote_case = Count('votes', filter=count_filter, output_field=BooleanField())
posts = Post.objects \
.annotate(is_voted=vote_case) \
.all().order_by('-created_at')
return render(request, 'main/feed.html', {'posts': posts,
'comments': comments})
got
TypeError at /
feed() missing 1 required positional argument: 'slug'
UPD: For the attemp above, I also did something:
set slug to None
def feed(request, slug=None):
And and moved the script to the for-loop (for post in posts)
This gave its results. Now everything works almost as it should, only there is a bug. When you click on the vote button, he votes for for the post below, and vice versa
OK - there's a fair bit to unpack here:
First, generally speaking, it looks you you want Ajax to handle the bulk of the work. The reason (or at least the initial reason) why that isn't working above is in how you replicate forms
For well constructed HTML, only one element per page should have a particular ID
Your form is generated like this
{% for post in posts %}
<div id="vote-section"> #This will repeat for every post
{% include 'main/votes.html' %}
</div>
What this means is that every form will have the same id, vote-section, so
success: function(resoponse){
$('#vote-section').html(resoponse['form'])
won't know where to write.
Similarly, in the forms on list, every button has id="vote"
This isn't an issue on the details page, because there's only one form and one vote/unvote button. On the list page, with multiple forms, it is.
So what to do about it?
First off, add a class to your button.
votes.html
<button type="submit" id="vote" class="vote-button" name="post_id" value="{{ post.id }}" btn="btn btn-outline">Unvote</button>
Next tweak your feed html so it uses IDs correctly. We'll use {{[forloop.counter][1]}} to generate unique IDs.
We'll also move the ajax into the loop, as the slug for each post is different in the url: generation section. We add the new div ID into the selector and the success function to make it unique.
feed.html
{% for post in posts %}
<div id="vote-section{{forloop.counter}}">
{% include 'main/votes.html' %}
</div>
...
<script>
$(document).ready(function(event){
$(document).on('click','#vote-section{{forloop.counter}} .vote-button', function(event){
event.preventDefault();
var pk = $(this).attr('value');
$.ajax({
type: 'POST',
//this needs to be in the for post in posts loop to get post.slug
url: "{% url 'main:post-vote' slug=post.slug %}",
data: {'id':pk, 'csrfmiddlewaretoken': '{{ csrf_token }}'},
dataType: 'json',
success: function(resoponse){
$('#vote-section{{forloop.counter').html(resoponse['form'])
console.log($('#vote-section{{forloop.counter}}').html(resoponse['form']));
},
error: function(rs, e){
console.log(rs.responseText);
}
})
});
});
</script>
{% endfor %}
Now there are probably ways to make this more efficient, but hopefully it should get you over the hump to where it works.
I got values of dropdown list which is expense.id and expense_type. In database I look for expense object which has id==expense.id sent by ajax in order to update its type (expense_type). So I need to send both expense.id and expense.type to sever using ajax. I dont know how to perform in jQuery as well as html. Below is my code I got error which is "Not Found: /polls/17/project_detail/ajax/update_form/"
<form action="/ajax/update_form/" method="POST" id="selection-form">
{% csrf_token %}
<select id="select_dropdown">
{% for expense in expenses %}
{% if project.id and expense.city %}
<option value="{{expense.id}}" selected="selected">{{expense.expense_type}}</option>
{% else %}
<option value="{{expense.id}}">{{expense.expense_type}}</option>
{% endif %}
{% endfor %}
</select>
<td><input type="submit" value="Save"></td>
</form>
=====js====
$('#selection-form').on('submit', function(event) {
event.preventDefault();
console.log("form_submitted");
create_post();
});
function create_post(){
console.log("update fucntion is working!");
var value = $("#select_dropdown").find(":selected").val();
var text = $("#select_dropdown option:selected").text();
$.ajax({
//url: "{% url 'update_form' %}",
url: "ajax/update_form/",
method: "POST",
data: {
"value": value,
"text": text,
//"pro_expense": pro_expense,
//"id": valueSelected,
csrfmiddlewaretoken: '{{ csrf_token }}',
},
//dataType: "json",
success: function(data){
console.log(data);
},
error: function(error_data){
console.log("error")
console.log(error_data)
}
});
return false;
};
====views.py=====
#csrf_exempt
def update_form(request):
if request.method == "POST" and request.is_ajax():
value = request.POST.get('value')
text = request.POST.get('text')
expense = Expense.objects.get(pk = value)
expense.expense_type = text
expense.save()
return HttpResponse({"result": "success"}, content_type="application/json")
===urls.py===
url(r'^(?P<project_id>[0-9]+)/project_detail/$', views.project_detail, name='project_detail'),
url(r'^ajax/update_form/$', views.update_form, name = 'update_form'),
error is "Not Found: /polls/17/project_detail/ajax/update_form/". please help. Any help will be highly appreciated!!
I want to hide form if user already pushed on the button. I tried to use a bit of JS code, it works well, but after refreshing page, button on form stay valid. It not a huge surprise for me)) I want hide form using Django templates, but it is not so easy as I thought.
my html :
<div class="who_come">
<p>Who come : </p>
{% for u in who_come %}
{%if u.visiter.username != request.user.username %}
<form class="form-inline" role="form" method="post" id="joinToEventForm">
{% csrf_token %}
<p align="left"><b ><button type="submit">I want join</button></b></p></b></p>
</form>
{% endif %}
{% endfor %}
<div id="who_come_links">
{% for u in who_come reversed %}
<p>{{u.visiter.username}}</p>
{% endfor %}
</div>
<script>
$('#joinToEventForm').submit(function() {
$(this).find("button[type='submit']").prop('disabled',true);
});
</script>
<script>
$('#joinToEventForm').on('submit', function(event){
event.preventDefault();
console.log("form submitted!") // sanity check
$.ajax({
type:'POST',
data:{
action: 'joinEvent',
csrfmiddlewaretoken:'{{ csrf_token }}'
},
success : function (data) {
//console.log(data);
var usernames = JSON.parse(data);
var html_str = '';
for (var i=0; i < usernames.length; i++) {
html_str += '<p>' + usernames[i] + '</p>';
}
$('#who_come_links').html(html_str);
}
});
});
</script>
</div>
my model :
class WhoComeOnEvent(models.Model):
visiter = models.ForeignKey(User, related_name='WhoComeOnEvent')
which_event = models.ForeignKey(Topic, related_name='WhoComeOnEvent')
in this place :
<p>Who come : </p>
{% for u in who_come %}
{%if u.visiter.username != request.user.username %}
<form class="form-inline" role="form" method="post" id="joinToEventForm">
{% csrf_token %}
<p align="left"><b ><button type="submit">I want join</button></b></p></b></p>
</form>
{% endif %}
{% endfor %}
i tried to check who already joined to event and if user that do request same that user in database table, then hide form. But this code doesn't work. It hide form no matter if user exist in db table or not. Second part is that has no connection to current event. Suppose django template that hide form in my case will work. It will check only row in table but it will ignore current it event or it different event (not sure, but i'm afraid of it).
my view :
def p(request, pk):
user = request.user
topic = get_object_or_404(Topic, pk=pk)
post = get_object_or_404(Post, pk=pk)
comment = Comments.objects.filter(pk=pk)
who_come = WhoComeOnEvent.objects.filter(which_event=topic.id)
if request.is_ajax() and request.POST.get('action') == 'joinEvent':
who_come_obj = WhoComeOnEvent.objects.create(
visiter=user,
which_event=post.topic
)
visitors_usernames = []
for w in who_come:
visitors_usernames.append(w.visiter.username)
return HttpResponse(json.dumps(visitors_usernames))
if request.method == 'POST':
form = CustomCommentForm(request.POST)
if form.is_valid():
comment = form.save(commit=False)
comment.post = post
comment.creator = user
comment = Comments.objects.create(
body=form.cleaned_data.get('body'),
creator=user,
post=post
)
return HttpResponseRedirect(request.META.get('HTTP_REFERER'))
# return render(request, 'post.html', {'post': post, 'topic': topic, 'comment': comment,
# 'form': form, 'who_come': who_come})
else:
form = CustomCommentForm()
return render(request, 'post.html', {'post': post, 'topic': topic, 'comment': comment,
'form': form, 'who_come': who_come})
Solution:
I found more elegant solution, just adding .distinct('visitor') to my who_come queryset.
If someone will read it question and found my solution helpful, notice, that objects still creating to the databese and it doesn't unique!
I am pretty new to Django and I try to create my first application. However I faced a problem now.
I have a form (to add Alert - my mdoel) with Django validation and a div with list of all alerts. If I fill all fields correctly the alert is added and my div with alerts is refreshed using ajax. The problem is with form validation.
Without ajax I was sending bound form with errorLists for every field. I used Django form API. It was working ok but I can't refresh the errorlist if adding a form couldn't succeed.
I am getting either no render of form or render without context - all fields are blank. Of course they shouldn't be blank if I made a mistake in one field and It was working OK without ajax.
Bunch of code, First this is the view method I call:
def add_alert(request):
report = __get_or_create_empty_Report(request)
if request.method == 'POST':
form = AlertForm(request.POST)
if form.is_valid():
alert_project = ""
alert_name = ""
alert_ticket = ""
alert_date = ""
alert_type = ""
alert_comment = ""
if form.cleaned_data.has_key('alert_project'):
alert_project = form.cleaned_data['alert_project']
if form.cleaned_data.has_key('alert_name'):
alert_name = form.cleaned_data['alert_name']
if form.cleaned_data.has_key('alert_ticket'):
alert_ticket = form.cleaned_data['alert_ticket']
if form.cleaned_data.has_key('alert_date'):
alert_date = form.cleaned_data['alert_date']
if form.cleaned_data.has_key('alert_type'):
alert_type = form.cleaned_data['alert_type']
if form.cleaned_data.has_key('alert_comment'):
alert_comment = form.cleaned_data['alert_comment']
alert = Alert()
alert.alt_prj_id = get_object_or_404(Project, prj_id=alert_project)
alert.alt_name = alert_name
alert.alt_ticket = alert_ticket
alert.alt_date = alert_date
alert.alt_type = alert_type
comment = Comment()
comment.com_value = alert_comment
comment.save()
alert.alt_com_id = comment
alert.alt_rep_id = report
alert.save()
alerts = Alert.objects.filter(alt_rep_id=report.rep_id)
return render(request, 'main/theform.html', {'form': form, 'alerts': alerts, 'error_message': "Alert has been added"})
else:
form = AlertForm()
alerts = Alert.objects.filter(alt_rep_id=report.rep_id)
return render(request, 'main/theform.html', {'form': form, 'alerts': alerts})
alerts = Alert.objects.filter(alt_rep_id=report.rep_id)
return render(request, 'main/theform.html', {'form': form, 'alerts': alerts, 'error_message': "Alert has NOT been added"})
Here's the form template:
{% extends 'main/base.html' %}
{% block content %}
<div id="alerts"> </div>
{% for alert in alerts %}
<p> {{ alert.alt_name }} </p>
{% endfor %}
<form class="col-md-12" action="{% url 'main:add_alert' %}" method="post">
{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Submit" />
</form>
{{ error_message }}
{% endblock %}
and simple script:
$(document).ready(function() {
//AJAX util
$('.add-alert-form').submit(function (e) {
e.preventDefault();
$.ajax({
type: "POST",
url: $(this).attr("action"),
data: $(this).serialize(),
success: function (data) {
$("#alerts").load(" #alerts");
}
});
});
}
I think I am doing it completly wrong but I have no idea what's the right way.
Take a look at https://docs.djangoproject.com/en/1.7/topics/forms/modelforms/
so your views would look like that:
if form.is_valid():
obj = form.save()
data = serializers.serialize('json', [obj,])
else:
data = json.dumps(dict([(k, [unicode(e) for e in v]) for k,v in form.errors.items()]))
return HttpResponse(data, mimetype='application/json')
I'm saving date in UTC. I wan't to change that date to automatic user timezone.
my settings
USE_TZ = True
my template
{% for sale in sales %}
date : {{sale.date}}
{% endfor %}
I tried django-tz-detect
https://github.com/adamcharnock/django-tz-detect
but I can't implement that correctly.
Please suggest a good way to solve this issue.
I got a solution from here
I created a view function
#login_required
#ajax_required
#require_GET
def set_user_timezone(request):
timezone = request.GET.get('timezone')
request.session["set_user_timezone"] = timezone
response_data = {}
response_data['status'] = 'true'
response_data['message'] = 'user timezone set successfully.'
return HttpResponse(json.dumps(response_data), mimetype='application/javascript')
context
if "set_user_timezone" in request.session:
user_session_ok = True
user_time_zone = request.session['set_user_timezone']
else:
user_session_ok = False
user_time_zone = "Asia/Kolkata"
in my base template
{% if not user_session_ok %}
<script type="text/javascript" src="{% static 'js/jstz.js' %}"></script>
<script>
$(document).ready(function(){
var timezone = jstz.determine();
var timezone_name = timezone.name();
$.ajax({
url : '/set-user-timezone/',
action : "GET",
data : {
timezone : timezone_name
},
success : function(data){
},
error : function(data){
}
})
});
</script>
{% endif %}
my sales template
{% for sale in sales %}
{% load tz %}
date : {{ sale.sale_date|timezone:user_time_zone }}
{% endfor %}
I don't know this is the correct method. but this solution works for me.