Làm thế nào để thực hiện SELECT MAX trong Django?


91

Tôi có một danh sách các đối tượng, làm cách nào để tôi có thể chạy truy vấn để cung cấp giá trị tối đa của một trường:

Tôi đang sử dụng mã này:

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

xếp hạng là một số nguyên

Câu trả lời:


172

Xem này . Mã của bạn sẽ giống như sau:

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

Bạn cũng có thể sử dụng điều này trên các tập truy vấn hiện có:

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

Nếu bạn cần phiên bản mô hình có chứa giá trị tối đa này, thì mã bạn đã đăng có lẽ là cách tốt nhất để làm điều đó:

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

Lưu ý rằng điều này sẽ xảy ra lỗi nếu bộ truy vấn trống, tức là nếu không có đối số nào phù hợp với truy vấn (vì [0]phần này sẽ nâng cao một IndexError). Nếu bạn muốn tránh hành vi đó và thay vào đó chỉ cần quay lại Nonetrong trường hợp đó, hãy sử dụng .first():

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

4
Tôi cần đối tượng đối số actuall có Max đó, để tôi có thể in trường chi tiết. Lệnh gọi args.aggregate (Max ('rating')) chỉ trả về xếp hạng cao nhất. Tôi đang tìm tranh luận có xếp hạng cao nhất.
Johnd

1
Có gì sai với mã thoát của bạn - Argument.objects.order_by ("- rating") [0]?
AdamKG

73

Django cũng có hàm ' mới nhất (field_name = None) ' để tìm mục nhập (giá trị tối đa) mới nhất. Nó không chỉ hoạt động với các trường ngày mà còn với các chuỗi và số nguyên.

Bạn có thể đặt tên trường khi gọi hàm đó:

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

Hoặc bạn đã có thể cung cấp tên trường đó trong dữ liệu meta mô hình của mình:

from django.db import models

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

Bây giờ bạn có thể gọi 'mới nhất ()' mà không có bất kỳ tham số nào:

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

3
Đây là một cách tuyệt vời để sử dụng latest(). Nếu bạn cần bản ghi với giá trị nhỏ nhất, bạn có thể sử dụng earliest().
SaeX

7
latest()và cũng earliest()hoạt động với trường không phải ngày tháng, nhưng đó là một tác dụng phụ của việc triển khai. Bạn nên sử dụng <your-queryset>.order_by('<interested-field>').first()hoặc <your-queryset>.order_by('<interested-field>').last()để đảm bảo mã của bạn sẽ vẫn hoạt động ngay cả khi các nhà phát triển Django sẽ thay đổi latest()earliest()triển khai để chỉ hoạt động với các trường ngày.
mrnfrancesco

Đây là một câu trả lời không tốt: 1) như đã nhận thấy trước đó, đó là chi tiết về việc triển khai và có thể được thay đổi trong tương lai 2) nó không dễ đọc - số tối đa không nhất thiết phải được lưu mới nhất (hoặc theo bất kỳ nghĩa nào khác)
Mikhail Gerasimov

47

Tôi đã thử nghiệm điều này cho dự án của mình, nó tìm thấy tối đa / phút trong thời gian 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)

Điều này được đảm bảo giúp bạn có được một trong những phần tử tối đa một cách hiệu quả, thay vì sắp xếp toàn bộ bảng và nhận phần đầu (xung quanh O (n * logn)).


8
Big-O đôi khi không có hiệu quả trong thực tế, đặc biệt là đối với n nhỏ hơn, trong đó hệ số và cách triển khai quan trọng. Mã của bạn ở dạng python / django, được biên dịch thành bytecode và có thể được tối ưu hóa hoặc không. Cơ sở dữ liệu có thể được viết bằng ngôn ngữ được tối ưu hóa và biên dịch theo hướng dẫn máy. Bên cạnh đó, cơ sở dữ liệu không có lý do thực sự để sắp xếp, nếu hàm chỉ tìm kiếm giá trị tối đa. Tôi muốn xem dữ liệu thời gian trước khi cảm thấy thoải mái khi sử dụng mã xây dựng thủ công qua một chức năng cơ sở dữ liệu tích hợp sẵn.
benevolentprof

5
@afahim Tôi không nghĩ mã bạn đăng là hoàn toàn chính xác. nếu hóa ra bạn có nhiều hơn một ứng dụng tối đa (giả sử bạn có hai Ứng dụng với 5 sao) bằng cách sử dụng "get" sẽ gây ra lỗi.
Raydel Miranda
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.