Reputation: 14254
I am building a simple application which has questions. Each question will have a binary vote (yes/no). I want to record the vote per user, so each user only gets one vote per question (similar to stack overflow or reddit).
I have a votes_no and votes_yes int field on the question. These need to be updated in a transaction every time a vote is added. Can I do this from the Vote model's save method?
class Question(models.Model):
part_isit = models.CharField(max_length=45)
part_if = models.CharField(max_length=90)
votes_no = models.IntegerField()
votes_yes = models.IntegerField()
author = models.ForeignKey(User)
create_date = models.DateField(auto_now_add=True)
VOTE_CHOICES = (
('Y', 'Yes'),
('N', 'No'),
)
class Vote(models.Model):
choice = models.CharField(max_length=1, choices=VOTE_CHOICES)
question = models.ForeignKey(Question)
author = models.ForeignKey(User)
create_date = models.DateField(auto_now_add=True)
def save(self):
# increment the questions vote totals
#save the vote
super(Vote, self).save();
Upvotes: 0
Views: 102
Reputation: 35619
I'd rewrite Igautier's method a bit differently:
class Question(models.Model):
# your defn
def count_yes(self):
return self.votes_set.filter(choice='Y')
def count_no(self):
return self.votes_set.filter(choice='N')
The reasoning behind this (and Igautier's answer) is that the data is all stored in the database already: having a total that is stored, whilst it prevents an extra query each time these methods are called, it means extra work when saving, and the chance that the data that is stored in the database in becomes conflicting.
If you find performance becomes an issue (and I strongly recommend you don't worry about it until it does), then you could look at caching querysets (try johnny-cache, for automatic, or another caching system), or even database triggers. I think that may move it out of your request loop: the database will look after updating the values whenever a write happens. Obviously, this will depend a bit on your DBMS.
And finally, it's not an answer to your question directly, but you mention one vote per user per question.
class Vote(models.Model):
# Your defn
class Meta:
unique_together = (
('author', 'question'),
)
Then you won't have to rely on application logic to keep that constraint true. You probably will to prevent users voting on their own questions though.
Upvotes: 1
Reputation: 11545
Would the following answer the question ?
class Question(models.Model):
blablabla #your definition
def count_yes(self):
return Vote.objects.filter(question__exact = self,
choice__exact = 'Y').count()
Upvotes: 1