Làm thế nào để tôi không bằng bộ lọc truy vấn Django?


664

Trong mô hình QuerySets của Django, tôi thấy rằng có một __gt__ltcho các giá trị so sánh, nhưng có một __ne/ !=/ <>( không bằng ?)

Tôi muốn lọc ra bằng cách sử dụng không bằng:

Thí dụ:

Model:
    bool a;
    int x;

tôi muốn

results = Model.objects.exclude(a=true, x!=5)

Các !=không phải là cú pháp chính xác. Tôi đã thử __ne, <>.

Tôi đã kết thúc bằng cách sử dụng:

results = Model.objects.exclude(a=true, x__lt=5).exclude(a=true, x__gt=5)

75
Kết quả = Model.objects.exclude (a = true) .filter (x = 5) có hoạt động không?
hughdbrown

3
@hughdbrown. Không. Truy vấn của bạn loại trừ tất cả a=trueđầu tiên và sau đó áp dụng x=5bộ lọc trên phần còn lại. Truy vấn dự định chỉ yêu cầu những người có a=truex!=5. Sự khác biệt là tất cả những người có a=truex=5cũng được lọc ra.
Mitchell van Zuylen

Câu trả lời:


688

Có lẽ các đối tượng Q có thể giúp đỡ cho vấn đề này. Tôi chưa bao giờ sử dụng chúng nhưng có vẻ như chúng có thể bị phủ nhận và kết hợp giống như các biểu thức trăn bình thường.

Cập nhật: Tôi mới dùng thử, có vẻ như nó hoạt động khá tốt:

>>> from myapp.models import Entry
>>> from django.db.models import Q

>>> Entry.objects.filter(~Q(id = 3))

[<Entry: Entry object>, <Entry: Entry object>, <Entry: Entry object>, ...]

16
@ JCLeitão: xem thêm câu trả lời của @ d4nt bên dưới để biết cú pháp trực quan hơn.
Paul D. Chờ đợi

610

Truy vấn của bạn dường như có một phủ định kép, bạn muốn loại trừ tất cả các hàng trong đó x không phải là 5, vì vậy nói cách khác, bạn muốn bao gồm tất cả các hàng trong đó x IS 5. Tôi tin rằng điều này sẽ thực hiện thủ thuật.

results = Model.objects.filter(x=5).exclude(a=true)

Để trả lời câu hỏi cụ thể của bạn, không có "không bằng" nhưng có lẽ vì django có cả hai phương thức "bộ lọc" và "loại trừ" để bạn luôn có thể chuyển vòng logic để có kết quả mong muốn.


2
@ d4nt: Tôi có thể sai, nhưng tôi nghĩ truy vấn nên làresults = Model.objects.filter(a=true).exclude(x=5)
Taranjeet

1
@Taranjeet: Tôi nghĩ bạn đã đọc sai truy vấn ban đầu. Phiên bản của d4nt là chính xác, vì OP muốn loại trừ (a = True) và phủ nhận loại trừ x = 5 (nghĩa là bao gồm nó).
Chuck

3
Tôi nghĩ điều này là sai vì một trường hợp (x = 4, a = false) sẽ bị loại trừ sai.
RemcoGerlich

4
@danigosa Điều đó có vẻ không đúng. Tôi chỉ thử bản thân mình, và thứ tự excludefiltercác cuộc gọi không tạo ra sự khác biệt có ý nghĩa. Thứ tự của các điều kiện trong WHEREmệnh đề thay đổi, nhưng điều đó quan trọng như thế nào?
coredumperror

4
@danigosa thứ tự loại trừ và bộ lọc không thành vấn đề.
EralpB

132

các field=valuecú pháp trong các truy vấn là một cách viết tắt cho field__exact=value. Điều đó có nghĩa là Django đặt các toán tử truy vấn trên các trường truy vấn trong các định danh . Django hỗ trợ các nhà khai thác sau:

exact
iexact
contains
icontains
in
gt
gte
lt
lte
startswith
istartswith
endswith
iendswith
range
year
month
day
week_day
isnull
search
regex
iregex

Tôi chắc chắn bằng cách kết hợp những thứ này với các đối tượng Q như Dave Vogt gợi ý và sử dụng filter()hoặc exclude()như Jason Baker gợi ý bạn sẽ nhận được chính xác những gì bạn cần cho bất kỳ truy vấn nào có thể.


cảm ơn điều này thật tuyệt tôi đã sử dụng một số thứ như thế này tg=Tag.objects.filter(user=request.user).exclude(name__regex=r'^(public|url)$')và nó hoạt động.
suhailvs

@suhail, xin lưu ý rằng không phải tất cả các cơ sở dữ liệu đều hỗ trợ cú pháp regex đó :)
Anoyz

2
i in icontains, iexactvà tương tự là viết tắt của "bỏ qua độ nhạy trường hợp". Nó không dành cho "nghịch đảo".
Ivy Trồng

Điều đáng chú ý là khi bạn đang sử dụng exclude()với nhiều thuật ngữ, bạn có thể muốn soạn thảo đề xuất với ORtoán tử, ví dụ exclude(Q(field1__queryop1=value1) | Q(field2__queryop2=value2))để loại trừ kết quả trong cả hai điều kiện.
clapas

98

Thật dễ dàng để tạo một tra cứu tùy chỉnh với Django 1.7. Có một __neví dụ tra cứu trong tài liệu chính thức của Django .

Bạn cần tạo bản tra cứu trước:

from django.db.models import Lookup

class NotEqual(Lookup):
    lookup_name = 'ne'

    def as_sql(self, qn, connection):
        lhs, lhs_params = self.process_lhs(qn, connection)
        rhs, rhs_params = self.process_rhs(qn, connection)
        params = lhs_params + rhs_params
        return '%s <> %s' % (lhs, rhs), params

Sau đó, bạn cần phải đăng ký nó:

from django.db.models.fields import Field
Field.register_lookup(NotEqual)

Và bây giờ bạn có thể sử dụng __netra cứu trong các truy vấn của mình như thế này:

results = Model.objects.exclude(a=True, x__ne=5)

88

Trong Django 1.9 / 1.10 có ba tùy chọn.

  1. Chuỗi excludefilter

    results = Model.objects.exclude(a=true).filter(x=5)
  2. Sử dụng Q()các đối tượng~toán tử

    from django.db.models import Q
    object_list = QuerySet.filter(~Q(a=True), x=5)
  3. Đăng ký chức năng tra cứu tùy chỉnh

    from django.db.models import Lookup
    from django.db.models.fields import Field
    
    @Field.register_lookup
    class NotEqual(Lookup):
        lookup_name = 'ne'
    
        def as_sql(self, compiler, connection):
            lhs, lhs_params = self.process_lhs(compiler, connection)
            rhs, rhs_params = self.process_rhs(compiler, connection)
            params = lhs_params + rhs_params
            return '%s <> %s' % (lhs, rhs), params

    Trình register_lookuptrang trí đã được thêm vào Django 1.8 và cho phép tra cứu tùy chỉnh như bình thường:

    results = Model.objects.exclude(a=True, x__ne=5)

1
object_list = QuerySet.filter (~ Q (a = True), x = 5): Hãy nhớ giữ tất cả các điều kiện khác không chứa Q sau những điều có chứa Q.
Bhumi Singhal

1
@MichaelHoffmann: A) sau đó bạn sẽ lọc trên một tập hợp dữ liệu nhỏ hơn sau khi loại trừ bằng cách sử dụng ~ Q vì vậy sẽ hiệu quả hơn. B) có lẽ trình tự theo cách khác xung quanh không hoạt động .. dun biết .. dun nhớ!
Bhumi Singhal

41

Trong khi với các mô hình, bạn có thể lọc với =, __gt, __gte, __lt, __lte, bạn có thể không sử dụng ne, !=hoặc <>. Tuy nhiên, bạn có thể đạt được bộ lọc tốt hơn khi sử dụng đối tượng Q.

Bạn có thể tránh xích QuerySet.filter()QuerySet.exlude(), và sử dụng điều này:

from django.db.models import Q
object_list = QuerySet.filter(~Q(field='not wanted'), field='wanted')

24

Trong khi chờ quyết định thiết kế. Trong khi đó, sử dụngexclude()

Trình theo dõi vấn đề Django có mục đáng chú ý # 5763 , có tiêu đề "Truy vấn không có toán tử lọc" không bằng " . Điều đáng chú ý là (kể từ tháng 4 năm 2016), nó đã được "mở 9 năm trước" (trong thời kỳ đồ đá Django), "đóng cửa 4 năm trước" và "thay đổi lần cuối 5 tháng trước".

Đọc qua các cuộc thảo luận, nó là thú vị. Về cơ bản, một số người cho __nenên được bổ sung trong khi những người khác nói exclude()là rõ ràng hơn và do đó __ne nên không được thêm vào.

(Tôi đồng ý với điều trước, vì đối số sau gần tương đương với việc nói Python không nên có !=vì nó đã ==notđã ...)


21

Sử dụng loại trừ và bộ lọc

results = Model.objects.filter(x=5).exclude(a=true)

18

Bạn nên sử dụng filterexcludethích điều này

results = Model.objects.exclude(a=true).filter(x=5)

8

Đoạn mã cuối cùng sẽ loại trừ tất cả các đối tượng trong đó x! = 5 và a là True. Thử cái này:

results = Model.objects.filter(a=False, x=5)

Hãy nhớ rằng, dấu = trong dòng trên đang gán Sai cho tham số a và số 5 cho tham số x. Đó không phải là kiểm tra sự bình đẳng. Do đó, thực sự không có cách nào để sử dụng biểu tượng! = Trong cuộc gọi truy vấn.


3
Đó không phải là 100% tương tự vì cũng có thể có các giá trị Null cho các trường đó.
MikeN

Điều này chỉ trả về những mục có a = Sai x = 5, nhưng trong câu hỏi, một trường hợp (a = false, x = 4) sẽ được đưa vào.
RemcoGerlich

1
results = Model.objects.filter(a__in=[False,None],x=5)
Jeremy

8

results = Model.objects.filter (a = True) .exclude (x = 5)
Tạo sql này:
chọn * từ bảngx trong đó a! = 0 và x! = 5
Sql phụ thuộc vào cách trường True / false của bạn được biểu diễn và công cụ cơ sở dữ liệu. Mã django là tất cả những gì bạn cần mặc dù.



6

Những gì bạn đang tìm kiếm là tất cả các đối tượng có a=false hoặc x=5 . Trong Django, |đóng vai trò là ORtoán tử giữa các truy vấn:

results = Model.objects.filter(a=false)|Model.objects.filter(x=5)

4

Điều này sẽ cho kết quả mong muốn của bạn.

from django.db.models import Q
results = Model.objects.exclude(Q(a=True) & ~Q(x=5))

cho không bằng bạn có thể sử dụng ~trên một truy vấn bằng nhau. rõ ràng, Qcó thể được sử dụng để đạt được truy vấn bằng nhau.


Vui lòng kiểm tra chỉnh sửa; bằng cách sử dụng và trong Q(a=True) and ~Q(x=5)đó sẽ đánh giá ~Q(x=5)như là đối số .exclude. Vui lòng đọc: docs.python.org/3/reference/expressions.html#boolean-operationsdocs.python.org/3/reference/ ,.
tzot

2

Xem ra cho rất nhiều câu trả lời không chính xác cho câu hỏi này!

Logic của Gerard là chính xác, mặc dù nó sẽ trả về một danh sách chứ không phải là một bộ truy vấn (có thể không quan trọng).

Nếu bạn cần một bộ truy vấn, sử dụng Q:

from django.db.models import Q
results = Model.objects.filter(Q(a=false) | Q(x=5))
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.