JuniorDev
JuniorDev

Reputation: 13

Django Order QuerySet based on ManyToManyField value

I have a business model as follows:

class Business(models.Model):

    class Meta:
        verbose_name_plural = "Businesses"

    name = models.CharField(max_length=60, null=False, verbose_name="Title")
    about = models.TextField(max_length=5000, null=True, verbose_name="Description", blank=True)
    upvote = models.ManyToManyField(Account, verbose_name="Upvote Count", blank=True)

The Account model is as follows:

class Account(models.Model):

    CHOICES = [('Male', 'Male'),Female', 'Female'),]

    class Meta:
        verbose_name_plural = "Accounts"

    name = models.CharField(max_length=60, null=False, verbose_name="Title")
    gender= models.CharField(max_length=6, null=True, verbose_name="Gender", choices=CHOICES)

I am trying to get a QuerySet that will be sorted by gender of the Account.

How do I achieve this?

So far I have achieved sorting by the upvote count.

Business.objects.all().order_by("upvote")

Upvotes: 1

Views: 141

Answers (2)

Abdul Aziz Barkat
Abdul Aziz Barkat

Reputation: 21787

You can use the Sum function [Django docs] with a Conditional Expression [Django docs] to annotate a value according to which you would order:

from django.db.models import Case, Sum, Value, When

Business.objects.annotate(
    order_value=Sum(
        Case(
            When(upvote__gender='Male', then=Value(1)),
            When(upvote__gender='Female', then=Value(-1)),
            default=Value(0)
        )
    )
).order_by('order_value')

The above query would give you Business objects with more upvotes by females first and males later, you can reverse the order by writing .order_by('-order_value') instead.

Upvotes: 1

yagus
yagus

Reputation: 1445

You can access fiels of related models by double underscore. See documentation here.

Try:

Business.objects.all().order_by("upvote__gender")

Upvotes: 0

Related Questions