Search code examples
djangoredditvote

reddit style voting with django


Hay i need to hand implemeneting a voting system into a model.

I've had a huge helping hand from Mike DeSimone making this work in the first place, but i need to expand upon his work.

Here is my current code

View

def show_game(request):
    game = Game.objects.get(pk=1)
    discussions = game.gamediscussion_set.filter(reply_to=None)
    d = {
        'game':game,
        'discussions':discussions
    }
    return render_to_response('show_game', d)

Template

<ul>
    {% for discussion in discussions %}
    {{ discussion.html }}
    {% endfor %}
</ul>

Model

class GameDiscussion(models.Model):
    game = models.ForeignKey(Game)
    message = models.TextField()
    reply_to = models.ForeignKey('self', related_name='replies', null=True, blank=True)
    created_on = models.DateTimeField(blank=True, auto_now_add=True)
    userUpVotes = models.ManyToManyField(User, blank=True, related_name='threadUpVotes')
    userDownVotes = models.ManyToManyField(User, blank=True, related_name='threadDownVotes')

    def html(self):
        DiscussionTemplate = loader.get_template("inclusions/discussionTemplate")
        return DiscussionTemplate.render(Context({
            'discussion': self,
            'replies': [reply.html() for reply in self.replies.all()]
    }))

DiscussionTemplate

<li>
    {{ discussion.message }}
    {% if replies %}
        <ul>
            {% for reply in replies %}
                {{ reply }}
            {% endfor %}
        </ul>
    {% endif %}
</li>

As you can see we have 2 fields userUpVotes and userDownVotes on the model, these will calculate how to order the discussions and replies.

How would i implement these 2 fields to order the replies and discussions based on votes?

Any help would be great!

EDIT

I've added a method to my model called vote_difference

    def vote_difference(self):
        return int(self.userUpVotes.count()) - int(self.userDownVotes.count())

I can user this in my templates to get the current vote, however i cannot use this in my view.py file to order by this value, is there anyway to include this value in my view?

EDIT (2)

I've slowly getting there, i need to annotate 2 fields and do a calculation on them, however it seems that i cannot do basic maths calculation with annotate.

Any ideas?

    discussions = game.gamediscussion_set.filter(reply_to=None).annotate( score= (Count('userUpVotes') - Count('userDownVotes')) ).order_by('-score')

Solution

  • The reddit algorithm is based on the formula for calculating gravity. I found it from this website

    Reddit Algorithm

    let t = (t1 – epoch)
    

    (where t1 is the time the post was made)

    let x be the number of up votes minus the number of down votes.
    

    Then,

    let y be:
    
    • 1 if there are more up votes than down votes,
    • -1 If there are more down voets than up votes,
    • 0 if there are the same number.

    Now Let

    z = max({x,1})
    

    And We Have

    ranking = C log10(z) + yt1
    
    Where C is a constant (C = 45000).