AttributeError: 'list' object has no attribute 'order_by' Python

Viewed 2665

I was trying to combine two queryset objects data by itertools chain python predefine function and sorting this with order_by. but i'm getting an AttributeError: 'list' object has no attribute 'order_by'. If anybody could figure out where i'm doing thing wrong then would be much appreciated. thank you so much in advance.

try:
    qs = ChatMessage.objects.filter(
            Q(from_user=user, to_user=to_user) |
            Q(from_user=to_user, to_user=user)
        )
except:
    raise ValidationError({"message":"bad request"})

data = UserChatMessageSerializer(qs, many=True, context={'request': request}).data
# qs.update(read_status=True)
for record in data:
    data1 = record['conversation']
    data2 = record['files']
    print(data2)
    from itertools import chain 
    all_results = list(chain(data1,data2)).order_by('-created_on')

output:
"all_results": [
        {
            "id": 19,
            "message": "sad",
            "created_on": "2021-01-08T19:43:12.232310Z",
            "read_status": false,
            "is_edited": false,
            "chat": 8
        },
        {
            "id": 20,
            "message": "sad",
            "created_on": "2021-01-09T06:32:30.381712Z",
            "read_status": false,
            "is_edited": false,
            "chat": 8
        },
]
4 Answers

You are getting a AttributeError because a list in Python does not have a order_by method (as the error states). Perhaps you meant to use the sort method?

I'm not sure what the data you're using looks like, but here is a simple example of ordering a list with the sort method and a lambda. Hopefully you should be able to adapt it for you own code:"

demo = [
    {"created_on": "2","another thing":40},
    {"created_on": "5","another thing":30},
    {"created_on": "1","another thing":60},
    {"created_on": "8","another thing":10}
]
demo.sort(key=lambda x: x["created_on"])
print(demo)
# [{'created_on': '1', 'another thing': 60}, {'created_on': '2', 'another thing': 40}, {'created_on': '5', 'another thing': 30}, {'created_on': '8', 'another thing': 10}]

You can not .order_by(…) a list. But you actually do not need this anyway. You can simply "merge" the two querysets like this

ChatMessage.objects.filter(
    Q(Queryset1) |
    Q(Queryset2)
  ).order_by('created_on')

or

try:
    qs = ChatMessage.objects.filter(
        Q(from_user=user, to_user=to_user) |
        Q(from_user=to_user, to_user=user)
    ).order_by('created_on')
except:
    raise ValidationError({"message":"bad request"})

data = UserChatMessageSerializer(qs, many=True, context={'request': 
request}).data
# qs.update(read_status=True)
for record in data:
    data1 = record['conversation']
    data2 = record['files']
    print(data2)
    from itertools import chain 
    all_results = list(chain(data1,data2))

Source

Chain order_by function to Queryset in following way and remove the order_by() call on list() object.

ChatMessage.objects.filter(
            Q(from_user=user, to_user=to_user) |
            Q(from_user=to_user, to_user=user)
        ).order_by('created_on')

order_by is a method of QuerySet class/datatype, while by using list method the object is list not QuerySet now. To merge two queryset you may use union method instead:

qs1.union(qs2).order_by('created_on')

As long as both data1 and data2 are QuerySet, which you can check with type() function, you can use method above.

If you like to sort a list, then sorting with a lambda function would be possible:

all_results = sorted(list(chain(d1,d2)), key=lambda item: item.created_on, reverse=True) 

Change reverse to True or False to control ascending or descending order.

Related