0

I am building a simple hacker news website and would like some help on how to integrate a ranking algorithm for submitted posts.

I understand that I can rank submitted posts via 'order_by', which I have done for now:

def index(request):
    submitted_items = Submission.objects.all().order_by('-votecount')[:20]

However, I would like to make the ranking more intelligent by factoring in the date at which the submission was made.

To give a little bit more context, I used this code block from a tutorial that I found as a base for trying to figure out how to implement such an algorithm:

class HomeView(TemplateView):
    template_name = 'home.html'

    def get_context_data(self, **kwargs):
        ctx = super(HomeView, self).get_context_data(**kwargs)

        now = timezone.now()
        submissions = Link.objects.all()
        for submission in submissions:
            num_votes = submission.upvotes.count()
            num_comments = submission.comment_set.count()

            date_diff = now - submission.submitted_on
            number_of_days_since_submission = date_diff.days

            submission.rank = num_votes + num_comments - number_of_days_since_submission

        sorted_submissions = sorted(submissions, key=lambda x: x.rank, reverse=True)
        ctx['submissions'] = sorted_submissions

        return ctx

But I couldn't get this to work in my own application.

I guess another way to phrase my question is this. Django/Python has a standard order_by() function that allows me to sort data, most simply in an ascending or descending order. Is there a way to create my own unique custom order_by() function that I can use?

Thanks in advance for the help!

HK boy
  • 1,398
  • 11
  • 17
  • 25
Bisb
  • 1
  • See https://stackoverflow.com/questions/1652577/django-ordering-queryset-by-a-calculated-field – Selcuk May 20 '19 at 13:13

1 Answers1

0

If you annotate your QuerySet with a new calculated value, you can order by that value. For example (you're not showing your Submission model so I don't know if these are the real fields of your model):

from django.db.models import F
from django.db.models.functions import ExtractDay
from django.utils import timezone

today = timezone.now().date
Submission.objects.annotate(rank=F('votecount') - ExtractDay(today - F('date')).order_by('-rank')
dirkgroten
  • 20,112
  • 2
  • 29
  • 42
  • Thank you for this response. Can you by any chance direct me to some documentation so that I can look into this? – Bisb May 20 '19 at 14:13
  • I've fixed my answer so that it can actually subtract a vote count (integer value) from the date difference: ExtractDay returns an integer number of days. – dirkgroten May 20 '19 at 14:26