I am making a small app that lets users vote items either up or down. I'm using Django (and new to it!).
I am just wondering, what is the best way to present the upvote link to the user. As a link, button or something else?
I have already done something like this in php with a different framework but I'm not sure if I can do it the same way. Should I have a method for up/down vote and then display a link to the user to click. When they click it, it performs the method and refreshes the page?
Here's the gist of my solution. I use images with jQuery/AJAX to handle clicks. Strongly influenced by this site. There's some stuff that could use some work (error handling in the client, for example -- and much of it could probably be refactored) but hopefully the code is useful to you.
The HTML:
<div class="vote-buttons"> {% ifequal thisUserUpVote 0 %} <img class="vote-up" src = "images/vote-up-off.png" title="Vote this thread UP. (click again to undo)" /> {% else %} <img class="vote-up selected" src = "images/vote-up-on.png" title="Vote this thread UP. (click again to undo)" /> {% endifequal %} {% ifequal thisUserDownVote 0 %} <img class="vote-down" src = "images/vote-down-off.png" title="Vote this thread DOWN if it is innapropriate or incorrect. (click again to undo)" /> {% else %} <img class="vote-down selected" src = "images/vote-down-on.png" title="Vote this thread DOWN if it is innapropriate or incorrect. (click again to undo)" /> {% endifequal %} </div> <!-- .votebuttons -->
The jQuery:
$(document).ready(function() { $('div.vote-buttons img.vote-up').click(function() { var id = {{ thread.id }}; var vote_type = 'up'; if ($(this).hasClass('selected')) { var vote_action = 'recall-vote' $.post('/ajax/thread/vote', {id:id, type:vote_type, action:vote_action}, function(response) { if (isInt(response)) { $('img.vote-up').removeAttr('src') .attr('src', 'images/vote-up-off.png') .removeClass('selected'); $('div.vote-tally span.num').html(response); } }); } else { var vote_action = 'vote' $.post('/ajax/thread/vote', {id:id, type:vote_type, action:vote_action}, function(response) { if (isInt(response)) { $('img.vote-up').removeAttr('src') .attr('src', 'images/vote-up-on.png') .addClass('selected'); $('div.vote-tally span.num').html(response); } }); } });
The Django view that handles the AJAX request:
def vote(request): thread_id = int(request.POST.get('id')) vote_type = request.POST.get('type') vote_action = request.POST.get('action') thread = get_object_or_404(Thread, pk=thread_id) thisUserUpVote = thread.userUpVotes.filter(id = request.user.id).count() thisUserDownVote = thread.userDownVotes.filter(id = request.user.id).count() if (vote_action == 'vote'): if (thisUserUpVote == 0) and (thisUserDownVote == 0): if (vote_type == 'up'): thread.userUpVotes.add(request.user) elif (vote_type == 'down'): thread.userDownVotes.add(request.user) else: return HttpResponse('error-unknown vote type') else: return HttpResponse('error - already voted', thisUserUpVote, thisUserDownVote) elif (vote_action == 'recall-vote'): if (vote_type == 'up') and (thisUserUpVote == 1): thread.userUpVotes.remove(request.user) elif (vote_type == 'down') and (thisUserDownVote ==1): thread.userDownVotes.remove(request.user) else: return HttpResponse('error - unknown vote type or no vote to recall') else: return HttpResponse('error - bad action') num_votes = thread.userUpVotes.count() - thread.userDownVotes.count() return HttpResponse(num_votes)
And the relevant parts of the Thread model:
class Thread(models.Model): # ... userUpVotes = models.ManyToManyField(User, blank=True, related_name='threadUpVotes') userDownVotes = models.ManyToManyField(User, blank=True, related_name='threadDownVotes')
Just plug and play:
RedditStyleVoting
Implementing reddit style voting for any Model with django-voting
http://code.google.com/p/django-voting/wiki/RedditStyleVoting
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With