Chọn các giá trị riêng biệt từ một trường bảng


104

Tôi đang cố gắng xoay xở để xoay quanh ORM của Django. Những gì tôi muốn làm là lấy một danh sách các giá trị riêng biệt trong một trường trên bảng của tôi .... tương đương với một trong các giá trị sau:

SELECT DISTINCT myfieldname FROM mytable

(Hay cách khác)

SELECT myfieldname FROM mytable GROUP BY myfieldname

Ít nhất tôi muốn làm theo cách Django trước khi sử dụng sql thô. Ví dụ, với một bảng:

id, street, city

1, Main Street, Hull

2, Đường khác, Thân tàu

3, Bibble Way, Leicester

4, Một cách khác, Leicester

5, High Street, Londidium

Tôi muốn nhận được:

Hull, Leicester, Londidium.

Câu trả lời:


202

Giả sử mô hình của bạn là 'Cửa hàng'

class Shop(models.Model):
    street = models.CharField(max_length=150)
    city = models.CharField(max_length=150)

    # some of your models may have explicit ordering
    class Meta:
        ordering = ('city')

Vì bạn có thể có thuộc tính Metalớp orderingđược đặt, bạn có thể sử dụng order_by()mà không có tham số để xóa bất kỳ thứ tự nào khi sử dụng distinct(). Xem tài liệu dưới order_by()

Nếu bạn không muốn bất kỳ thứ tự nào được áp dụng cho một truy vấn, thậm chí không phải là thứ tự mặc định, hãy gọi order_by () không có tham số.

distinct()trong ghi chú, nơi nó thảo luận về các vấn đề sử dụng distinct()với đặt hàng.

Để truy vấn DB của bạn, bạn chỉ cần gọi:

models.Shop.objects.order_by().values('city').distinct()

Nó trả về một nhị phân

hoặc là

models.Shop.objects.order_by().values_list('city').distinct()

Cái này trả về một ValuesListQuerySetcái mà bạn có thể truyền tới a list. Bạn cũng có thể thêm flat=Truevào values_listđể làm phẳng kết quả.

Xem thêm: Nhận các giá trị riêng biệt của Queryset theo trường


29
Trên thực tế, nó hoạt động. Tuy nhiên! Tôi không thể làm cho nó hoạt động trên tất cả các mô hình của mình. Weidly, nó hoạt động trên một số nhưng không hiệu quả với những người khác. Đối với những người có thứ tự Meta, nó không hoạt động. Vì vậy, bạn phải xóa thứ tự trên bộ truy vấn trước. mô hình.Shop.objects.order_by (). giá trị ('thành phố').
diff

2
Điều quan trọng cần lưu ý là values_listkhông thực sự trả lại danh sách. Nó trả về một cái gì đó giống như một bộ truy vấn. Tôi thấy hữu ích khi luôn sử dụng list () xung quanh các lệnh gọi value_list.
dheerosaur

8
values_listtrả về ValuesListQuerySet là một trình lặp. Truyền tới danh sách có thể hữu ích, nhưng cũng có thể ảnh hưởng đến hiệu suất khi tất cả các hàng phải được đánh giá cùng một lúc, đặc biệt là với các tập dữ liệu lớn.
Peter Kilczuk

3
Các Meta: ordering = ()"tính năng" của ORM Django và objects.distinct()vs objects.ordering().distinct()gây ra chúng ta giờ nhầm lẫn. Phải có nhãn dán cảnh báo an toàn cho người tiêu dùng trên sản phẩm đó;) Chúng tôi có thể thực hiện chính sách thuộc tính không đặt hàng theo Meta để ngăn chặn hành vi gãi đầu trong tương lai.
hobs

Bạn có thể tắt Metalớp orderingvà giải quyết vấn đề distinctbằng cách sử dụng order_by()không có tham số. Đó là trong các tài liệu QuerySet API dưới order_by()" Nếu bạn không muốn bất kỳ đặt hàng để được áp dụng cho một truy vấn, thậm chí không phải là tự mặc định, cuộc gọi order_by()không có tham số. "
Đánh dấu Mikofski

11

Ngoài việc vẫn còn rất thích hợp câu trả lời của jujule , tôi thấy nó khá quan trọng để cũng nhận thức được ý nghĩa của order_by()trên distinct("field_name")truy vấn. Tuy nhiên, đây là một tính năng chỉ Postgres!

Nếu bạn đang sử dụng Postgres và nếu bạn xác định một tên trường mà truy vấn phải khác biệt, thì order_by()cần phải bắt đầu bằng cùng một tên trường (hoặc các tên trường) trong cùng một chuỗi (có thể có nhiều trường hơn sau đó).

Ghi chú

Khi bạn chỉ định tên trường, bạn phải cung cấp order_by () trong QuerySet và các trường trong order_by () phải bắt đầu bằng các trường trong phân biệt (), theo cùng một thứ tự.

Ví dụ, SELECT DISTINCT ON (a) cung cấp cho bạn hàng đầu tiên cho mỗi giá trị trong cột a. Nếu bạn không chỉ định đơn hàng, bạn sẽ nhận được một số hàng tùy ý.

Nếu bạn muốn trích xuất danh sách các thành phố mà bạn biết các cửa hàng ở đó, ví dụ về jujule sẽ phải được điều chỉnh cho phù hợp:

# returns an iterable Queryset of cities.
models.Shop.objects.order_by('city').values_list('city', flat=True).distinct('city')  

2

Ví dụ như:

# select distinct code from Platform where id in ( select platform__id from Build where product=p)
pl_ids = Build.objects.values('platform__id').filter(product=p)
platforms = Platform.objects.values_list('code', flat=True).filter(id__in=pl_ids).distinct('code')
platforms = list(platforms) if platforms else []
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.