0

I am first trying to sort by created_on descending and then using the same product_users queryset and applying sorted function on foreign_key user object where field is name.

product_users = ProductUser.objects.filter(entity=entity).order_by('-created_on')
product_users = sorted(product_users, key=lambda pu(pu.user.name.lower(), pu.status))

I want to apply order by descending on second column pu.status

90's_jaddu
  • 53
  • 8

3 Answers3

0

For sorting by multiple attributes, you should make lambda function to return a tuple of attributes instead one. so you can try:

sorted(product_users, key=lambda pu: (pu.user.name.lower(), pu.status)

But if you want to sort ascending by former attribute and sort descending by latter attribute, you can use a function as explained in

Python Sort Function Documentation:


def multisort(xs, specs):
    for key, reverse in reversed(specs):
        xs.sort(key=attrgetter(key), reverse=reverse)
    return xs

So xs is our list that we want to sort and specs is a list including tuples as each tuple for an attribute: ('attr_name', reverse)

  • how to implement the same def multisort(xs, specs): to my scenario, the function seems quite confusing. – 90's_jaddu Nov 18 '20 at 13:18
  • I have come up with this approach which works: product_users = sorted(product_users, key=lambda pu: (pu.user.name.lower(), sorted(pu.status, reverse=True))) – 90's_jaddu Nov 18 '20 at 13:20
  • Okay pls let me know what is the right approach to achieve what i need. thanks in advance. – 90's_jaddu Nov 18 '20 at 13:31
  • I think it's very complicated to use inline sorted, Or maybe impossible. Only way that i think is working definitely is to use 2 sorted functions. First by status in descending order and second by .user.name.lower() in ascending order. – Sajjad Sanikhani Nov 18 '20 at 13:34
  • yes i am using two sorted functions which first sort gives sort by name and second sort by status in descending order. – 90's_jaddu Nov 18 '20 at 13:38
0

Django 1.8+ , you can annotate user's name in lowercase to the queryset and then use order_by to sort

from django.db.models.functions import Lower
       
product_users  = product_users.annotate(name_lower=Lower('user__name'))
product_users  = product_users.order_by('name_lower', '-status')

Edit: If you really need to use sorted function for some reason, please try the answer in this link

Arjun Ariyil
  • 386
  • 3
  • 14
  • I have come up with this approach which works: product_users = sorted(product_users, key=lambda pu: (pu.user.name.lower(), sorted(pu.status, reverse=True))) – 90's_jaddu Nov 18 '20 at 13:20
  • The right way to do this in Django is to first annotate and then use order_by. Using sorted for such sorting is complicated. – Arjun Ariyil Nov 19 '20 at 08:46
0

Solved it by using two sorted function on same go for both first sort by status descending and then sort by user name ascending.

product_users = sorted(product_users, key=lambda pu: (sorted(pu.status, reverse=True), pu.user.name.lower()))
90's_jaddu
  • 53
  • 8