Kiểm tra bộ truy vấn trống trong Django


183

Thành ngữ được đề xuất để kiểm tra xem một truy vấn có trả về kết quả nào không?
Thí dụ:

orgs = Organisation.objects.filter(name__iexact = 'Fjuk inc')
# If any results
    # Do this with the results without querying again.
# Else, do something else...

Tôi cho rằng có một số cách khác nhau để kiểm tra điều này, nhưng tôi muốn biết người dùng Django có kinh nghiệm sẽ làm như thế nào. Hầu hết các ví dụ trong các tài liệu chỉ bỏ qua trường hợp không tìm thấy gì ...

Câu trả lời:


205
if not orgs:
    # Do this...
else:
    # Do that...

5
Điều này dường như cũng được ưu tiên trong tài liệu, ví dụ: docs.djangoproject.com/en/1.8/topics/http/shortype/#id7
Wtower

1
@Wtower Mã mà bạn đề cập có hợp đồng để tăng 404 nếu biểu thức lọc không đạt bất kỳ bản ghi nào hoặc tạo ra listkết quả nếu có bản ghi. Mã ở đó sẽ đánh vào cơ sở dữ liệu chỉ một lần. Nếu họ đã sử dụng exist()hoặc count()trước tiên kiểm tra xem có hồ sơ nào được trả về hay không, họ sẽ truy cập cơ sở dữ liệu hai lần (một lần để kiểm tra, một lần để nhận hồ sơ). Đây là một tình huống cụ thể. Nó không đòi hỏi rằng trong trường hợp chung , phương pháp ưa thích để biết liệu truy vấn có trả về các bản ghi hay không là sử dụng doif queryset:...
Louis

1
@Louis mã tôi đề cập đến chỉ là một ví dụ mà nó chứa một dòng if not my_objects:để chứng minh rằng đây là cách họ làm điều đó trong các tài liệu. Tất cả những thứ khác là hoàn toàn không liên quan vì vậy tôi không nhận được quan điểm của bạn. Họ cũng có thể thực hiện một ngàn truy vấn và nó vẫn hoàn toàn không liên quan vì đây không phải là điểm của câu trả lời này, mà tôi nói rõ rằng tôi đồng ý.
Wtower

1
@Wtower Đó chỉ là một lời giải thích về cách thức get_object_or_404hoạt động, không phải là một cách ưa thích để kiểm tra xem có bất kỳ yếu tố nào tồn tại trong một bộ truy vấn hay không. Làm danh sách () trên bộ truy vấn sẽ tìm nạp mọi đối tượng trên bộ truy vấn, điều này sẽ tệ hơn truy vấn hai lần nếu có nhiều hàng được trả về.
minmaxavg

1
Để có câu trả lời chi tiết hơn, hãy xem câu trả lời của @ leonid-shvechikov dưới đây: sử dụng .exists()sẽ hiệu quả hơn nếu qs sẽ không được đánh giá.
guival

191

Kể từ phiên bản 1.2, Django có Truy vấn. phương thức tồn tại () hiệu quả nhất:

if orgs.exists():
    # Do this...
else:
    # Do that...

Nhưng nếu bạn định đánh giá Queryset thì tốt hơn nên sử dụng:

if orgs:
   ...

Để biết thêm thông tin, hãy đọc tài liệu QueryIn.exists () .


.exists () chỉ dành cho .filter (), có cái gì cho .get () không?
cuộn

.getkhông trả về một bộ truy vấn. Nó trả về một đối tượng. Vì vậy, google cho điều đó
Aseem

Nó chỉ hiệu quả hơn đáng kể nếu bạn có một Truy vấn
Nathan Jones

16

Nếu bạn có một số lượng lớn các đối tượng, điều này có thể (đôi khi) nhanh hơn nhiều:

try:
    orgs[0]
    # If you get here, it exists...
except IndexError:
    # Doesn't exist!

Trong một dự án tôi đang làm việc với một cơ sở dữ liệu khổng lồ, not orgshơn 400 ms và orgs.count()là 250ms. Trong các trường hợp sử dụng phổ biến nhất của tôi (những trường hợp có kết quả), kỹ thuật này thường giảm xuống dưới 20ms. (Một trường hợp tôi tìm thấy, đó là 6.)

Tất nhiên, có thể lâu hơn nhiều, tùy thuộc vào việc cơ sở dữ liệu phải tìm bao xa để tìm kết quả. Hoặc thậm chí nhanh hơn, nếu nó tìm thấy một cách nhanh chóng; YMMV.

EDIT: Đây sẽ thường chậm hơn so với orgs.count()nếu kết quả là không tìm thấy, đặc biệt là nếu điều kiện bạn đang lọc trên là một trong những hiếm; do đó, nó đặc biệt hữu ích trong các chức năng xem trong đó bạn cần đảm bảo chế độ xem tồn tại hoặc ném http404. (Ở đâu, người ta sẽ hy vọng, mọi người đang yêu cầu các URL tồn tại thường xuyên hơn không.)


10

Để kiểm tra sự trống rỗng của một bộ truy vấn:

if orgs.exists():
    # Do something

hoặc bạn có thể kiểm tra mục đầu tiên trong bộ truy vấn, nếu nó không tồn tại, nó sẽ trả về None:

if orgs.first():
    # Do something

7
if orgs.exists()được bao phủ bởi một câu trả lời được cung cấp khoảng 5 năm trước câu trả lời này. Điều duy nhất câu trả lời này mang đến cho cái bàn có lẽ là mới if orgs.first(). (Ngay cả điều này còn gây tranh cãi: nó có khác biệt nhiều so với thực hiện orgs[0] đề xuất khoảng 5 năm trước không?) Bạn nên phát triển phần đó của câu trả lời: khi nào người ta muốn làm điều này thay vì các giải pháp khác được đề xuất trước đó?
Louis

9

Cách hiệu quả nhất (trước django 1.2) là:

if orgs.count() == 0:
    # no results
else:
    # alrigh! let's continue...

5
.exists () dường như thậm chí còn hiệu quả hơn
dzida

5
Ngoại trừ .exists () đã được thêm vào vài tháng sau bình luận của tôi và Django 1.2 (kết hợp API đó) đã được phát hành ~ 8 tháng sau đó. Nhưng cảm ơn vì đã bỏ phiếu và không bận tâm kiểm tra sự thật.
Bartosz

4
Xin lỗi, tôi đã thêm chỉnh sửa nhỏ vào câu trả lời của bạn để làm cho nó chính xác hơn và được bình chọn tích cực.
dzida

4

Tôi không đồng ý với vị ngữ

if not orgs:

Nó nên

if not orgs.count():

Tôi gặp vấn đề tương tự với tập kết quả khá lớn (~ 150k kết quả). Toán tử không bị quá tải trong Truy vấn, vì vậy kết quả thực sự được giải nén dưới dạng danh sách trước khi kiểm tra được thực hiện. Trong trường hợp của tôi thời gian thực hiện đã đi xuống bởi ba đơn đặt hàng.


6
__nonzero__ đã bị quá tải trong Truy vấn. Nếu kết quả không được lưu trong bộ nhớ cache (nó không bao giờ được sử dụng lần đầu tiên của bộ truy vấn), hành vi của __nonzero__ là lặp lại tất cả các thành phần trong bộ truy vấn. Điều này là rất xấu nếu bộ lớn.
hedleyroos

0

Bạn cũng có thể sử dụng điều này:

if(not(orgs)): #if orgs is empty else: #if orgs is not empty

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.