A generic ratings module. The field itself appends two additional fields on the model, for optimization reasons. It adds <field>_score
, and <field>_votes
fields, which are both integer fields.
This fork extends upon David Cramer's django-ratings in a way to make ratings generic to better support and adapt to different rating systems, such as votings, star ratings, like/dislike, flags and others.
You will need to add djangoratings
to your INSTALLED_APPS
:
INSTALLED_APPS = ( 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'djangoratings', )
Finally, run python manage.py syncdb
in your application's directory to create the tables.
The way django-ratings is built requires you to attach a RatingField to your models. This field will create two columns, a votes column, and a score column. They will both be prefixed with your field name:
from djangoratings.fields import RatingField class MyModel(models.Model): rating = RatingField(range=5) # 5 possible rating values, 1-5
Alternatively you could do something like:
from djangoratings.fields import AnonymousRatingField class MyModel(models.Model): rating = AnonymousRatingField(range=10)
If you'd like to use the built-in weighting methods, to make it appear more difficult for an object
to obtain a higher rating, you can use the weight
kwarg:
class MyModel(models.Model): rating = RatingField(range=10, weight=10)
RatingField
allows the following options:
lower = 0
- The lower value in the range for which values are accepted. For example, a lower value of -1, says the voting scores start at -1.upper = 2
- The upper value in the range for which values are accepted. For example, an upper value of 1, says the highest possible voting score is 1.range = 2
- Upper and range are synonymous. For example, a range of 2, says there are 2 possible vote scores (provided lower is not set, or is 0).can_change_vote = False
- Allow the modification of votes that have already been made.allow_delete = False
- Allow the deletion of existent votes. Works only ifcan_change_vote = True
allow_anonymous = False
- Whether to allow anonymous votes.use_cookies = False
- Use COOKIES to authenticate user votes. Works only ifallow_anonymous = True
.values = [lower ... upper]
- List of strings accepted as alternative to score integer values. For example,['clear', 'favorite']
would make it so the voting system accepts eigher 'clear' or 'favorite' in addition to 0 and 1, respectively.titles = []
- List of strings used to have verbose names the voting scores. For example,[_("Clear"), _("Favorite")]
.widget_template = 'djangoratings/_rating.html'
- Accepts the template name used to display the widget.
Also available there are VotingField
, FavoriteField
and FlagField
, with their anonymous alternatives:
from djangoratings.fields import VotingField class MyModel(models.Model): rating = VotingField() # accepting 'down', 'clear' and 'up'
VotingField
's default options are:
lower = -1
upper = 1
values = ['down', 'clear', 'up']
titles = [_("Down"), _("Clear"), _("Up")]
widget_template = 'djangoratings/_voting.html'
FavoriteField
's default options are:
lower = 0
upper = 1
values = ['clear', 'favorite']
titles = [_("Clear"), _("Favorite")]
widget_template = 'djangoratings/_favorite.html'
FlagField
's default options are:
lower = 0
upper = 1
values = ['clear', 'flag']
titles = [_("Clear"), _("Flag")]
widget_template = 'djangoratings/_flag.html'
And adding votes is also simple:
myinstance.rating.add(score=1, user=request.user, ip_address=request.META['REMOTE_ADDR'], request.COOKIES) # last param is optional - only if you use COOKIES-auth
Retrieving votes is just as easy:
myinstance.rating.get_rating_for_user(request.user, request.META['REMOTE_ADDR'], request.COOKIES) # last param is optional - only if you use COOKIES-auth
New You're also able to delete existent votes (if deletion enabled):
myinstance.rating.delete(request.user, request.META['REMOTE_ADDR'], request.COOKIES) # last param is optional - only if you use COOKIES-auth
Accessing information about the rating of an object is also easy:
# these do not hit the database myinstance.rating.votes myinstance.rating.score
How you can order by top-rated using an algorithm (example from Nibbits.com source):
# In this example, ``rating`` is the attribute name for your ``RatingField`` qs = qs.extra(select={ 'rating': '((100/%s*rating_score/(rating_votes+%s))+100)/2' % (MyModel.rating.range, MyModel.rating.weight) }) qs = qs.order_by('-rating')
Get overall rating for your instance on a scale [0-range]:
myinstance.rating.get_rating()
Get recent ratings for your instance:
# This returns ``Vote`` instances. myinstance.rating.get_ratings()[0:5]
Get the percent of voters approval:
myinstance.rating.get_percent()
Get that same percentage, but excluding your weight
:
myinstance.rating.get_real_percent()
The best way to use the generic views is by extending it, or calling it within your own code:
from djangoratings.views import AddRatingFromModel urlpatterns = patterns('', url(r'rate-my-post/(?P<object_id>\d+)/(?P<score>\d+)/', AddRatingFromModel(), { 'app_label': 'blogs', 'model': 'post', 'field_name': 'rating', }), )
Another example, on Nibbits we use a basic API interface, and we simply call the AddRatingView
within our own view:
from djangoratings.views import AddRatingView # For the sake of this actually looking like documentation: params = { 'content_type_id': 23, 'object_id': 34, 'field_name': 'ratings', # this should match the field name defined in your model 'score': 1, # the score value they're sending } response = AddRatingView()(request, **params) if response.status_code == 200: if response.content == 'Vote recorded.': request.user.add_xp(settings.XP_BONUSES['submit-rating']) return {'message': response.content, 'score': params['score']} return {'error': 9, 'message': response.content}
New: For now COOKIE name has fixed format: "vote-{{ content_type.id }}.{{ object.id }}.{{ rating_field.key }}[:6]" and COOKIE value is simple datetime-stamp.
Example: vote-15.56.2c5504=20101213101523456000
And this COOKIE lives in user's browser for 1 year (this period is also fixed for now)
This feature may change in the future
New in 0.3.5: There is now a setting, RATINGS_VOTES_PER_IP
, to limit the number of unique IPs per object/rating-field combination. This is useful if you have issues with users registering multiple accounts to vote on a single object:
RATINGS_VOTES_PER_IP = 3
Right now django-ratings has limited support for template tags, and only for Django.
Retrieves the Vote
cast by a user on a particular object and
stores it in a context variable. If the user has not voted, the
context variable will be 0:
{% rating_by_request request on instance.field as vote %}
If you are using Coffin, a better approach might be:
{% with instance.field_name.get_rating_for_user(request.user, request.META['REMOTE_ADDR'], request.COOKIES) as vote %} Do some magic with {{ vote }} {% endwith %}
To use the request
context variable you will need to add django.core.context_processors.request
to the TEMPLATE_CONTEXT_PROCESSORS
setting.
It is recommended that you use rating_by_request as you will gain full support for anonymous users if they are enabled
Retrieves the Vote
cast by a user on a particular object and
stores it in a context variable. If the user has not voted, the
context variable will be 0:
{% rating_by_user user on instance.field as vote %}
Uses widget_template
passed to the field to render the rating field widget:
{% rating_widget on instance.field %}
If you want to use a different widget_template
, pass the template name as:
{% rating_widget on instance.field using "template_name.html" %}
The context is passed to the template and additionally, the template receives:
content_type
- The content type of the instance object.instance
- The object instance.model
- The model name for the object.app_label
- The app label for the object.object_id
- The object instance ID.field_name
- The field name.had_voted
- If the user has voted previously, the voted score.votes
- Number of total votes.score
- The overall voting score for the object.vote
- The overall voting score for the object, as an integer.percent
- The overall voting score for the object, as a percentage.real_percent
- The overall voting score for the object, as a percentage (without taking into account the weights).positive
- Number of positive votes (when applicable).negative
- Number of negative votes (when applicable).ratings
- a list ofchecked
,value
andtitle
. For example:[ { 'checked': False, 'value': 'clear', 'title: 'Clear' }, { 'checked': True, 'value': 'favorite', 'title: 'Favorite' }, ]