Rabid Ratings for Django
By: Jens in ajax | django | python | snipplet | tools
For my new pet project i'd like to have some nice fancy starlike rating stuff, but without stars :-) Luckily i found one over at ajaxrain called Rabid Ratings. It uses nice looking hearts and is a out of the box combo with ajax and a php backend. Yep there was my prob again, php. So i took a look at the php backend and decided to quickly port the main logic to my django app and make it available to the public.
The code consists of a tag with its own html, a simple view and model. I think it self-explanatory.
Our model with a generic key not bound to django models:
class Rating(models.Model): key = models.CharField("RatingKey", max_length=256, unique=True) total_rating = models.IntegerField("Total Rating Sum" , default=0) total_votes = models.IntegerField("Total votes", default=0) max_stars=5 def get_star_rating(self): star_rating = 0 if self.total_votes > 0: star_rating = round(float( float(self.total_rating/self.total_votes) / float(100/self.max_stars)) , 1) return star_rating def get_percent(self): if self.total_votes > 0: return round(float(self.total_rating/self.total_votes) , 0) return 0 class Meta: pass class Admin: list_display = ('key','total_rating','total_votes',)
The view called by the ajax voting part:
def do_vote(request): return_value = "" try: rating = Rating.objects.get(key=request.POST['id']) rating.total_votes += 1 rating.total_rating += int(request.POST['vote']) rating.save() return_value = "%s/%s stars ( %s votes)" % ( rating.get_star_rating(), rating.max_stars, rating.total_votes) except: pass return HttpResponse(return_value)
The tag:
def show_rating(context, rating_key): rating, created = Rating.objects.get_or_create(key=rating_key) return { 'rating_key': rating_key, 'total_votes': rating.total_votes, 'total_ratings': rating.total_rating, 'rating': rating.get_star_rating(), 'percent': rating.get_percent(), 'max_stars': rating.max_stars } register.inclusion_tag("plaza/ratings.html", takes_context=True)(show_rating)
The tags html template:
<div id="rabidRating-{{rating_key}}-{{rating}}_{{max_stars}}" class="rabidRating ratingUnrated"> <div class="wrapper"> <span class="ratingFill" style="width:{{percent}}%;"> <span class="ratingStars"></span> </span> </div> <div id="rabidRating-{{rating_key}}-description" class="ratingText"> {{rating}}/{{max_stars}} stars ({{total_votes}} votes) </div> </div>
Map the view in your app and change the ajax call in ratings.js, add the tag somewhere and voila happy voting :-)




on 1 July 2008 at 15:01 sean said …
Hi
Thanks for sharing this code, really useful. There is a nasty little bug in there though - in the view
rating = Rating.objects.get(id=request.POST['id'])
should be
rating = Rating.objects.get(key=request.POST['id'])
thanks again,
Sean
on 2 July 2008 at 05:15 Jens said …
Thanks Sean, i fixed the code above and in my app too ;-)
on 28 February 2009 at 17:31 Ben said …
Awesome work. I have it working for the most part but onMouseOut... or MooTools equiv., the stars do not revert to overall score, they simply stay put, wherever the user left them. Any ideas on what im doing wrong? How do I troubleshoot this sort of thing?
Also, should add a ip address to the model schema. currently, refreshing the page will allow the user to vote again.
on 27 June 2009 at 15:47 luislop said …
Hi. im so newbie, can you helpme with this: "Map the view in your app and change the ajax call in ratings.js, add the tag somewhere" and I hace this error "Exception Value:
name 'register' is not defined" whe I define "from django import template
register = template.Library()" i get this error: "Exception Value:
'show_rating' is not a valid tag library: Could not load template library from django.templatetags.show_rating, No module named show_rating" thanks for help me :)
on 27 June 2009 at 17:07 luislop said …
Ok Jens, I read better and it worked :) why dont handle Duplicate votes in a specific time? like in the demo http://msteigerwalt.com/widgets/ratings/v1.4/- Thanks.
on 14 August 2009 at 07:02 Jens said …
If i remember right the original php script did try to identify double votes by ip address, which is imho not suitable at all, for example only one vote from voters behind a proxy would be count in a certain time. Sure there are other ways, but honestly i didnt need any :-)