I'm new to Django, moved from PHP with Propel ORM engine. So here is what I am currently doing in Django. My website has several models like
Each of them can can be liked or disliked by a user (only once) changing the model's rating by +1 or -1.
In terms of PHP i would create a behavior, for ex. "Rateable" which would add some fields and methods to the original model and query class (like get_rating()
, order_by_rating()
, etc) and create a separate table for each model, for ex. book_rating_history
which would hold all of the ratings for each object, to determine if the user can or can't change the rating (or show all object's ratings, if necessary). So all I would need to do is to specify the "Rateable" behavior in the model declaration, and that's all. Everything else is done automatically.
The question is - how to solve this in Django? How to model correctly? Which techniques do you use in similar cases?
You'll want to store ratings and books separately, something like this (untested).
from django.contrib.auth.models import User
from django.db import models
from django.db.models import Sum
class BookRating(models.Model):
user = models.ForeignKey(User)
book = models.ForeignKey('Book')
# you'll want to enforce that this is only ever +1 or -1
rating = models.IntegerField()
class Meta:
unique_together = (('user', 'book'),)
class Book(models.Model):
title = models.CharField(max_length = 50)
def rating(self):
return BookRating.objects.filter(book = self).aggregate(Sum('rating'))
unique_together
enforces that each user can only rate a given book once.
You can then use this something like:
book = Book.objects.get(pk = 1)
rating = book.rating()
Add a comment if you have problems with this - I've not tested it, but hopefully this is enough to get you started.
You can probably avoid each object (books, publishers, comments, articles) having a separate rating object using content types, if you want.
Alternatively, you might consider looking at existing reusable apps that handle liking, like django-likes or phileo.