From 95060813801f7cd5d32537dfd940beca6e52cb6c Mon Sep 17 00:00:00 2001 From: luxcem Date: Sat, 22 Apr 2017 16:13:18 +0200 Subject: [PATCH] up and down votes --- apps/core/test_app.py | 5 +++ apps/rp/models/__init__.py | 0 apps/rp/models/votes.py | 91 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 apps/core/test_app.py create mode 100644 apps/rp/models/__init__.py create mode 100644 apps/rp/models/votes.py diff --git a/apps/core/test_app.py b/apps/core/test_app.py new file mode 100644 index 0000000..d141e01 --- /dev/null +++ b/apps/core/test_app.py @@ -0,0 +1,5 @@ +from core.apps import CoreConfig + + +def test_init(): + assert CoreConfig.name == 'core' diff --git a/apps/rp/models/__init__.py b/apps/rp/models/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/apps/rp/models/votes.py b/apps/rp/models/votes.py new file mode 100644 index 0000000..82b8720 --- /dev/null +++ b/apps/rp/models/votes.py @@ -0,0 +1,91 @@ +from django.db import models +from django.db.models import Sum, F +from django.contrib.contenttypes.fields import GenericForeignKey +from django.contrib.contenttypes.fields import GenericRelation +from django.contrib.contenttypes.models import ContentType +from django.contrib.auth.models import User + + +class UnDVotes(models.Model): + """ + Up and down vote model + """ + user = models.ForeignKey( + User, + on_delete=models.CASCADE, + ) + + #: Upvote, True for upvote, false for downvote + score = models.IntegerField(default=True) + # Django generic relation + content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) + object_id = models.PositiveIntegerField() + #: The Voted object + content_object = GenericForeignKey("content_type", "object_id") + + def __str__(self): + return "{}:{}:{}".format(self.user, self.content_object, self.score) + + +class UnDVotedMixin(models.Model): + """ + A mixin to attach to a model that has up and down votes + """ + #: Votes + und_votes = GenericRelation(UnDVotes) + #: Score of the model + und_score = models.IntegerField(default=0) + + def upvote(self, user): + diff_score = 0 + try: + # Already voted content + vote = self.und_votes.get(user=user) + if vote.score == 1: + # Cancel previous upvote + vote.delete() + diff_score = -1 + else: + # Previously downvoted + vote.score = 1 + vote.save() + diff_score = 2 + except: + vote = UnDVotes(content_object=self, user=user, score=1) + vote.save() + diff_score = 1 + + self.__class__.objects.filter(id=self.id).update( + und_score=F("und_score") + diff_score) + + def downvote(self, user): + diff_score = 0 + try: + # Already voted content + vote = self.und_votes.get(user=user) + if vote.score == -1: + # Cancel previous downvote + vote.delete() + diff_score = 1 + else: + # Previously upvoted + vote.score = -1 + vote.save() + diff_score = -2 + except: + vote = UnDVotes(content_object=self, user=user, score=-1) + vote.save() + diff_score = -1 + + # Update self score, use update and filter to avoid triggering signals + self.__class__.objects.filter(id=self.id).update( + und_score=F("und_score") + diff_score) + + def update_und_score(self): + """Reset score to the correct count (should not be necessary)""" + score = self.und_votes.aggregate(Sum("score"))["score__sum"] or 0 + # Update self score, use update and filter to avoid triggering signals + self.__class__.objects.filter(id=self.id).update(und_score=score) + + class Meta: + abstract = True -- GitLab