Những cách tốt để sắp xếp một bộ truy vấn? - Django


111

những gì tôi đang cố gắng làm là:

  • nhận 30 tác giả có điểm cao nhất ( Author.objects.order_by('-score')[:30])

  • đặt hàng các tác giả bởi last_name


Bất kỳ đề xuất?


4
@RH: vậy làm thế nào về việc kiểm tra câu trả lời của AlexMartelli là giải pháp chính xác? (không phải là anh ta cần bất kỳ đại diện hơn, trừ khi anh ta đang diễn ra sau đó anh chàng Skeet ...)
PaulMcG

Câu trả lời:


190

Thế còn

import operator

auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))

Trong Django 1.4 và mới hơn, bạn có thể đặt hàng bằng cách cung cấp nhiều trường.
Tham khảo: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by

order_by (* trường)

Theo mặc định, các kết quả trả về bởi a QuerySetđược sắp xếp theo bộ thứ tự được cung cấp bởi orderingtùy chọn trong Meta của mô hình. Bạn có thể ghi đè điều này trên cơ sở per-QuerySet bằng cách sử dụng order_byphương pháp này.

Thí dụ:

ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]

Kết quả trên sẽ được sắp xếp theo scorethứ tự giảm dần, sau đó last_nametăng dần. Dấu âm phía trước "-score"cho biết thứ tự giảm dần. Thứ tự tăng dần được ngụ ý.


1
@Alex: grazie alex! Điều đó thật tuyệt, tôi muốn đọc về mô-đun điều hành!
RadiantHex

3
Điều này có hiệu quả hơn Author.objects.order_by ('- score', 'last_name') [: 30] không?
Brian Luft

4
@Brian - nếu "hiệu quả hơn" bạn có nghĩa là "đúng hơn" thì có, của nó. :) Giải pháp của bạn giữ cho các tác giả được sắp xếp khá nhiều theo điểm số và chỉ xếp theo thứ tự bảng chữ cái những tác giả có cùng số điểm (đó là cách các phím phụ hoạt động). Alex chỉ ra cách lấy các kết quả, sau đó áp dụng một thứ tự sắp xếp hoàn toàn khác cho chúng (sử dụng key = operator.attrgetter để xác định một biểu thức khóa cho mỗi đối tượng), đó là những gì OP yêu cầu.
PaulMcG

@Paul: đó không phải là những gì tôi đã hỏi, câu trả lời của Alex là câu trả lời chính xác!
RadiantHex

4
Tại sao không thực hiện chức năng phím sắp xếp lambda x: x.last_name? Nó ngắn hơn, dài hơn và không cần nhập bất kỳ.
Krzysztof Szularz

12

Tôi chỉ muốn minh họa rằng các giải pháp tích hợp sẵn (chỉ dành cho SQL) không phải lúc nào cũng là những giải pháp tốt nhất. Lúc đầu, tôi nghĩ rằng vì QuerySet.objects.order_byphương thức của Django chấp nhận nhiều đối số, bạn có thể dễ dàng xâu chuỗi chúng:

ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]

Nhưng, nó không hoạt động như bạn mong đợi. Trường hợp cụ thể, đầu tiên là danh sách các tổng thống được sắp xếp theo điểm số (chọn top 5 để dễ đọc hơn):

>>> auths = Author.objects.order_by('-score')[:5]
>>> for x in auths: print x
... 
James Monroe (487)
Ulysses Simpson (474)
Harry Truman (471)
Benjamin Harrison (467)
Gerald Rudolph (464)

Sử dụng giải pháp của Alex Martelli cung cấp chính xác 5 người hàng đầu được sắp xếp theo last_name:

>>> for x in sorted(auths, key=operator.attrgetter('last_name')): print x
... 
Benjamin Harrison (467)
James Monroe (487)
Gerald Rudolph (464)
Ulysses Simpson (474)
Harry Truman (471)

Và bây giờ là order_bycuộc gọi kết hợp :

>>> myauths = Author.objects.order_by('-score', 'last_name')[:5]
>>> for x in myauths: print x
... 
James Monroe (487)
Ulysses Simpson (474)
Harry Truman (471)
Benjamin Harrison (467)
Gerald Rudolph (464)

Như bạn có thể thấy, kết quả giống như kết quả đầu tiên, có nghĩa là nó không hoạt động như bạn mong đợi.


13
Kết quả # 3 của bạn đang sắp xếp giảm dần theo điểm và sau đó theo last_name IFF bất kỳ đối tượng nào có cùng điểm. Vấn đề là không có đối tượng nào trong tập kết quả của bạn có cùng số điểm nên chỉ có '-score' là ảnh hưởng đến thứ tự sắp xếp. Thử đặt số điểm của 3 tác giả là 487 và chạy lại # 3.
istruble

Vâng, tôi hiểu điều đó. Tôi thực sự chỉ muốn minh họa rằng các giải pháp tích hợp sẵn (chỉ dành cho SQL) không phải lúc nào cũng là những giải pháp tốt nhất.
jathanism

3
Nó đã làm chính xác những gì tôi mong đợi: thứ tự từ vựng (điều này hơi tầm thường nếu khóa sắp xếp đầu tiên đều khác biệt).
Jonas Kölker

5

Đây là một cách cho phép quan hệ đối với điểm giới hạn.

author_count = Author.objects.count()
cut_off_score = Author.objects.order_by('-score').values_list('score')[min(30, author_count)]
top_authors = Author.objects.filter(score__gte=cut_off_score).order_by('last_name')

Bạn có thể có hơn 30 tác giả trong top_authors theo cách này và điều min(30,author_count)đó xảy ra nếu bạn có ít hơn 30 tác giả.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.