วิธีการทำ SELECT MAX ใน Django


93

ฉันมีรายการวัตถุที่ฉันจะเรียกใช้แบบสอบถามเพื่อให้ค่าสูงสุดของเขตข้อมูลได้อย่างไร:

ฉันใช้รหัสนี้:

def get_best_argument(self):
    try:
        arg = self.argument_set.order_by('-rating')[0].details
    except IndexError:
        return 'no posts'
    return arg

คะแนนเป็นจำนวนเต็ม

คำตอบ:


177

ดูนี้ รหัสของคุณจะเป็นดังนี้:

from django.db.models import Max
# Generates a "SELECT MAX..." query
Argument.objects.aggregate(Max('rating')) # {'rating__max': 5}

คุณยังสามารถใช้สิ่งนี้กับชุดแบบสอบถามที่มีอยู่:

from django.db.models import Max
args = Argument.objects.filter(name='foo') # or whatever arbitrary queryset
args.aggregate(Max('rating')) # {'rating__max': 5}

หากคุณต้องการโมเดลอินสแตนซ์ที่มีค่าสูงสุดนี้รหัสที่คุณโพสต์น่าจะเป็นวิธีที่ดีที่สุด:

arg = args.order_by('-rating')[0]

โปรดทราบว่าสิ่งนี้จะเกิดข้อผิดพลาดหากชุดแบบสอบถามว่างเปล่ากล่าวคือหากไม่มีอาร์กิวเมนต์ที่ตรงกับข้อความค้นหา (เนื่องจาก[0]ส่วนจะเพิ่มค่าIndexError) หากคุณต้องการหลีกเลี่ยงพฤติกรรมนั้นและกลับไปใช้Noneในกรณีนั้นแทนให้ใช้.first():

arg = args.order_by('-rating').first() # may return None

4
ฉันต้องการอ็อบเจ็กต์แอคชูออลที่มีค่าสูงสุดดังนั้นฉันจึงสามารถพิมพ์ฟิลด์รายละเอียดได้ การเรียก args.aggregate (Max ('rating')) จะส่งกลับการจัดอันดับสูงสุด ฉันกำลังมองหาอาร์กิวเมนต์ที่มีคะแนนสูงสุด
Johnd

1
เกิดอะไรขึ้นกับรหัสออกของคุณ - Argument.objects.order_by ("- rating") [0]
AdamKG

74

Django ยังมีฟังก์ชัน' latest (field_name = None) ' ที่ค้นหารายการล่าสุด (ค่าสูงสุด) ไม่เพียง แต่ใช้งานได้กับฟิลด์วันที่เท่านั้น แต่ยังใช้กับสตริงและจำนวนเต็ม

คุณสามารถตั้งชื่อฟิลด์เมื่อเรียกใช้ฟังก์ชันนั้น:

max_rated_entry = YourModel.objects.latest('rating')
return max_rated_entry.details

หรือคุณสามารถตั้งชื่อฟิลด์นั้นในข้อมูลเมตาของโมเดลของคุณได้แล้ว:

from django.db import models

class YourModel(models.Model):
    #your class definition
    class Meta:
        get_latest_by = 'rating'

ตอนนี้คุณสามารถเรียก 'latest ()' โดยไม่มีพารามิเตอร์ใด ๆ :

max_rated_entry = YourModel.objects.latest()
return max_rated_entry.details

3
latest()นี้เป็นวิธีที่ดีของการใช้ earliest()หากคุณต้องการบันทึกที่มีค่าต่ำสุดที่คุณสามารถใช้
SaeX

7
latest()และใช้earliest()งานได้กับฟิลด์ที่ไม่ใช่วันที่ด้วย แต่เป็นผลข้างเคียงของการใช้งาน คุณควรใช้<your-queryset>.order_by('<interested-field>').first()หรือ<your-queryset>.order_by('<interested-field>').last()เพื่อให้แน่ใจว่าโค้ดของคุณจะยังใช้งานได้แม้ว่านักพัฒนา Django จะเปลี่ยนlatest()และearliest()ใช้งานกับฟิลด์วันที่เท่านั้น
mrnfrancesco

นี่เป็นคำตอบที่ไม่ดี: 1) ตามที่สังเกตเห็นแล้วก่อนหน้านี้เป็นรายละเอียดของการใช้งานและสามารถเปลี่ยนแปลงได้ในอนาคต 2) ไม่สามารถอ่านได้มากนัก - จำนวนสูงสุดไม่จำเป็นต้องบันทึกล่าสุด (หรือในแง่อื่น ๆ )
Mikhail Gerasimov

49

ฉันได้ทดสอบสิ่งนี้สำหรับโครงการของฉันพบว่าสูงสุด / นาทีในเวลา O (n):

from django.db.models import Max

# Find the maximum value of the rating and then get the record with that rating. 
# Notice the double underscores in rating__max
max_rating = App.objects.aggregate(Max('rating'))['rating__max']
return App.objects.get(rating=max_rating)

สิ่งนี้รับประกันได้ว่าจะทำให้คุณได้รับหนึ่งในองค์ประกอบสูงสุดอย่างมีประสิทธิภาพแทนที่จะจัดเรียงทั้งตารางและได้อันดับต้น ๆ (รอบ O (n * logn))


8
Big-O บางครั้งก็ไม่สามารถปฏิบัติได้ในทางปฏิบัติโดยเฉพาะอย่างยิ่งสำหรับ n ที่เล็กกว่าซึ่งสัมประสิทธิ์และการนำไปใช้มีความสำคัญ โค้ดของคุณอยู่ใน python / django ซึ่งคอมไพล์เป็น bytecode และอาจปรับให้เหมาะสมหรือไม่ก็ได้ ฐานข้อมูลมักจะเขียนด้วยภาษาที่ปรับให้เหมาะสมและรวบรวมตามคำสั่งของเครื่อง นอกจากนี้ฐานข้อมูลยังไม่มีเหตุผลที่แท้จริงในการจัดเรียงหากฟังก์ชันกำลังมองหาค่าสูงสุดเท่านั้น ฉันต้องการดูข้อมูลเวลาก่อนที่ฉันจะสามารถใช้รหัสสร้างมือผ่านฟังก์ชันฐานข้อมูลในตัวได้
เมตตาธรรม

5
@afahim ฉันไม่คิดว่ารหัสที่คุณโพสต์จะถูกต้องสมบูรณ์ หากปรากฎว่าคุณมีมากกว่าหนึ่งสูงสุด (สมมติว่าคุณมีสองแอพที่มี 5 ดาว) โดยใช้ "get" จะทำให้เกิดข้อผิดพลาด
Raydel Miranda
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.