วิธีที่ดีในการจัดเรียงแบบสอบถาม? - Django


112

สิ่งที่ฉันพยายามทำคือ:

  • ได้รับ 30 ผู้แต่งที่มีคะแนนสูงสุด ( Author.objects.order_by('-score')[:30])

  • สั่งผู้เขียนโดย last_name


ข้อเสนอแนะใด ๆ ?


4
@RH: แล้วลองตรวจสอบคำตอบของ AlexMartelli ว่าเป็นคำตอบที่ถูกต้องได้อย่างไร (ไม่ใช่ว่าเขาต้องการตัวแทนอีกต่อไปเว้นแต่ว่าเขาจะไปตามผู้ชาย Skeet คนนั้น ... )
PaulMcG

คำตอบ:


191

แล้ว

import operator

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

ใน Django 1.4 และใหม่กว่าคุณสามารถสั่งซื้อได้โดยระบุหลายช่อง
อ้างอิง: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by

order_by (* ช่อง)

ตามค่าเริ่มต้นผลลัพธ์ที่ส่งกลับโดย a QuerySetจะเรียงลำดับตามลำดับทูเปิลที่กำหนดโดยorderingตัวเลือกใน Meta ของโมเดล คุณสามารถแทนที่สิ่งนี้บนพื้นฐานต่อ QuerySet โดยใช้order_byวิธีการ

ตัวอย่าง:

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

ผลลัพธ์ข้างต้นจะเรียงscoreลำดับจากlast_nameมากไปหาน้อยจากน้อยไปมาก เครื่องหมายลบด้านหน้า"-score"หมายถึงลำดับจากมากไปหาน้อย ลำดับจากน้อยไปมากเป็นนัย


1
@ อเล็กซ์: กราซี่อเล็กซ์! เยี่ยมมากฉันไม่อยากอ่านเกี่ยวกับโมดูลตัวดำเนินการ!
RadiantHex

3
มีประสิทธิภาพมากกว่า Author.objects.order_by ('- score', 'last_name') [: 30] หรือไม่
Brian Luft

4
@ ไบรอัน - ถ้าโดย "มีประสิทธิภาพมากขึ้น" คุณหมายถึง "ถูกต้องมากขึ้น" ใช่แล้ว :) วิธีแก้ปัญหาของคุณช่วยให้ผู้เขียนเรียงลำดับตามคะแนนได้ดีและเรียงตามตัวอักษรของผู้เขียนเหล่านั้นด้วยคะแนนเดียวกันเท่านั้น (ซึ่งเป็นวิธีการทำงานของคีย์รอง) Alex แสดงวิธีรับผลลัพธ์จากนั้นใช้ลำดับการจัดเรียงที่แตกต่างกันโดยสิ้นเชิง (โดยใช้ key = operator.attrgetter เพื่อกำหนดนิพจน์คีย์ต่อออบเจ็กต์) ซึ่งเป็นสิ่งที่ OP ขอ
PaulMcG

@ พอล: นั่นไม่ใช่สิ่งที่ฉันถาม แต่คำตอบของอเล็กซ์คือคำตอบที่ถูกต้อง!
RadiantHex

4
ทำไมไม่สร้างฟังก์ชันคีย์การเรียงลำดับlambda x: x.last_name? สั้นกว่าละเอียดกว่าและไม่ต้องนำเข้าใด ๆ
Krzysztof Szularz

12

ฉันแค่อยากจะแสดงให้เห็นว่าโซลูชันในตัว (เฉพาะ SQL) ไม่ใช่โซลูชันที่ดีที่สุดเสมอไป ตอนแรกฉันคิดว่าเนื่องจากQuerySet.objects.order_byวิธีการของ Django ยอมรับข้อโต้แย้งหลายข้อคุณจึงสามารถเชื่อมโยงได้อย่างง่ายดาย:

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

แต่มันไม่ได้ผลตามที่คุณคาดหวัง ในประเด็นอันดับแรกคือรายชื่อประธานาธิบดีเรียงตามคะแนน (เลือก 5 อันดับแรกเพื่อให้อ่านง่ายขึ้น):

>>> 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)

การใช้โซลูชันของ Alex Martelli ซึ่งให้บริการคน 5 อันดับแรกอย่างแม่นยำเรียงตาม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)

และตอนนี้การorder_byโทรรวม:

>>> 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)

อย่างที่คุณเห็นมันเป็นผลลัพธ์เดียวกันกับผลลัพธ์แรกซึ่งหมายความว่ามันไม่ได้ผลอย่างที่คุณคาดหวัง


13
ผลลัพธ์ของคุณ # 3 กำลังเรียงลำดับจากมากไปหาน้อยตามคะแนนจากนั้นตาม last_name IFF วัตถุใด ๆ ที่มีคะแนนเท่ากัน ปัญหาคือไม่มีวัตถุใดในชุดผลลัพธ์ของคุณที่มีคะแนนเท่ากันดังนั้นมีเพียง '-score' เท่านั้นที่มีผลต่อลำดับการจัดเรียง ลองตั้งคะแนนผู้เขียน 3 คนเป็น 487 แล้วเรียกใช้ # 3 อีกครั้ง
istruble

ใช่ฉันเข้าใจแล้ว ฉันแค่อยากจะแสดงให้เห็นว่าโซลูชันในตัว (เฉพาะ SQL) ไม่ใช่โซลูชันที่ดีที่สุดเสมอไป
jathanism

3
มันทำตามที่ฉันคาดไว้อย่างแน่นอน: การเรียงลำดับคำศัพท์ (ซึ่งเป็นเรื่องเล็กน้อยถ้าคีย์การเรียงลำดับแรกแตกต่างกันทั้งหมด)
Jonas Kölker

5

นี่คือวิธีที่ช่วยให้มีความสัมพันธ์สำหรับคะแนนที่ถูกตัดออก

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')

คุณอาจได้ผู้เขียนมากกว่า 30 คนใน top_authors ด้วยวิธีนี้และในmin(30,author_count)กรณีที่คุณมีผู้เขียนน้อยกว่า 30 คน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.