Philip Mutua
Philip Mutua

Reputation: 6891

How to assign ranking on objects based on a value in a queryset

I have a queryset that returns a list of menus that and I want to assign each Menu a rank based on the number of votes accumulated is there a way I can achieve this using django Query Expressions? I'm also open to any other suggestions.

The queryset is as follows:

qs = Menu.objects.filter(Q(created_at__date__iexact=todays_date)).order_by('-votes')

And the Menu class model is shown below:

class Menu(models.Model):
    """Represents menu class model"""
    restaurant = models.ForeignKey(Restaurant,null=True,blank=True,on_delete=models.CASCADE)
    file = models.FileField(upload_to='menus/')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    uploaded_by = models.CharField(max_length=50, null=True, blank=True)
    votes = models.IntegerField(default=0)

After serializing the queryset returns the following data:

[
  {
        "id": 10,
        "file": "https://res.cloudinary.com/dw9bllelz/raw/upload/v1/media/menus/index_ah660c.jpeg",
        "restaurant": "Burger King",
        "votes": 10,
        "created_at": "2021-06-03T09:33:05.505482+03:00"
    },
    {
        "id": 9,
        "file": "https://res.cloudinary.com/dw9bllelz/raw/upload/v1/media/menus/index_ah660c.jpeg",
        "restaurant": "Texas Plates",
        "votes": 2,
        "created_at": "2021-06-03T09:33:05.505482+03:00"
    },
    {
        "id": 8,
        "file": "https://res.cloudinary.com/dw9bllelz/raw/upload/v1/media/menus/index_ah660c.jpeg",
        "restaurant": "Carlito Dishes",
        "votes": 2,
        "created_at": "2021-06-03T09:33:05.505482+03:00"
    },
      {
        "id": 7,
        "file": "https://res.cloudinary.com/dw9bllelz/raw/upload/v1/media/menus/index_ah660c.jpeg",
        "restaurant": "Kram Dishes",
        "votes": 1,
        "created_at": "2021-06-03T09:33:05.505482+03:00"
    },

]

Upvotes: 0

Views: 2048

Answers (1)

Abdul Aziz Barkat
Abdul Aziz Barkat

Reputation: 21807

You can either use the index of the object in the array as its index or you can use Window functions [Django docs] and use the Rank or DenseRank (Reference [Django docs]) function to compute the ranks as per your need:

from django.db.models import F, Window
from django.db.models.functions import Rank


qs = Menu.objects.filter(
    Q(created_at__date__iexact=todays_date)
).annotate(
    rank=Window(
        expression=Rank(),
        order_by=F('votes').desc(),
    )
)


for menu in qs:
    print(menu.rank, menu.votes)

Upvotes: 3

Related Questions