2009-03-26 67 views
465

Trong queryset mô hình Django, tôi thấy rằng có một __gt__lt cho các giá trị comparitive, nhưng là có một __ne/!=/<>Tôi làm cách nào để lọc không bình đẳng trong bộ lọc truy vấn Django?

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

Ví dụ:

Model: 
    bool a; 
    int x; 

tôi muốn

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

!= không đúng cú pháp. Tôi đã thử __ne, <>.

tôi đã kết thúc bằng:

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

Kết quả sẽ là = Model.objects.exclude (a = true) .filter (x = 5) đã hoạt động chưa? – hughdbrown

+1

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

Trả lời

488

Có thể Q objects có thể giúp ích 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 python bình thường.

Cập nhật: Tôi Chỉ cần thử nó ra, có vẻ như làm việc 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>, ...] 
+10

@ JCLeitão: xem thêm [@ d4nt's answer below] (http://stackoverflow.com/a/4139956/20578) cho cú pháp trực quan hơn. –

7

Các bit cuối cùng của mã sẽ loại trừ tất cả đối tượng trong đó x = 5 và một là True!. Hãy thử điều này:

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

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

+3

Đó không phải là 100% cùng một điều vì cũng có thể có giá trị Null cho các trường đó. – MikeN

+0

Điều này trả về chỉ những mục có = False _and_ x = 5, nhưng trong câu hỏi một thể hiện (a = false, x = 4) sẽ được bao gồm. – RemcoGerlich

+1

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

95

các field=value cú pháp trong các truy vấn là viết tắt của field__exact=value. Đó là để nói rằng Django puts query operators on query fields in the identifiers. Django hỗ trợ các nhà khai thác như 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 rằng bằng cách kết hợp chúng với các đối tượng Q như Dave Vogt suggests và sử dụng filter() hoặc exclude() như Jason Baker suggests bạn sẽ nhận được chính xác những gì bạn cần cho chỉ là về bất kỳ truy vấn có thể.

+0

cảm ơn điều này thật tuyệt vời. 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

+0

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

+0

i trong 'icontains',' iexact' và tương tự là viết tắt của "ignore case sensitive". Nó không dành cho "nghịch đảo". –

443

Truy vấn của bạn dường như có âm 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 có 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ả "bộ lọc" và "loại trừ" phương pháp có sẵn để bạn có thể luôn luôn chỉ cần chuyển logic vòng để có được những mong muốn kết quả.

+0

@ d4nt: Tôi có thể sai, nhưng tôi cho rằng truy vấn phải là 'results = Model.objects.filter (a = true) .exclude (x = 5)' – Taranjeet

+1

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

+2

Tôi nghĩ rằng điều này là sai vì một thể hiện (x = 4, a = false) sẽ bị loại trừ sai. – RemcoGerlich

37

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 lọc tốt hơn khi sử dụng đối tượng Q.

Bạn có thể tránh chaining QuerySet.filter()QuerySet.exlude(), và sử dụng này:

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

Thật dễ dàng để tạo ra một tra cứu tùy chỉnh với Django 1.7. Có một ví dụ tra cứu __ne trong Django official documentation.

Bạn cần phải tạo các tra cứu bản thân đầu tiên:

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 tra cứu __ne trong các truy vấn của bạn như thế này:

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

Câu trả lời xuất sắc và nghĩa đen là câu trả lời duy nhất thực sự trả lời câu hỏi. –

12

Bạn nên sử dụng filterexclude như thế này

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

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

  1. Chain exclude and filter

    results = Model.objects.exclude(a=true).filter(x=5) 
    
  2. Sử dụng Q() objects~ operator

    from django.db.models import Q 
    object_list = QuerySet.filter(~Q(a=True), x=5) 
    
  3. Đăng ký một custom lookup function

    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 
    

    Các trang trí register_lookup đã được bổ sung trong 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 khi có chứa Q. –

11

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

Các Django theo dõi vấn đề đáng chú ý đã entry #5763, tựa đề "QuerySet không có một 'không bằng' nhà điều hành bộ lọc". Điều đáng chú ý vì (tính đến tháng 4 năm 2016) là "đã mở 9 năm trước" (trong thời kỳ đồ đá Django), "đã đóng 4 năm trước" và "thay đổi lần cuối 5 tháng trước".

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

(Tôi đồng ý với trước đây, bởi vì đối số thứ hai là tương đương với nói Python không nên có != vì nó đã ==not đã ...)

3

gì bạn đang tìm kiếm là tất cả đối tượng có hoặc là a=falsehoặcx=5. Trong Django, | đóng vai trò như OR điều hành giữa queryset:

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

results = Model.objects.filter(a = True).exclude(x = 5)
Generetes sql này:
select * from tablex where a != 0 and x !=5
Các sql phụ thuộc vào cách Đúng lĩnh vực của bạn/False được đại diện, và động cơ sở dữ liệu. Mã django là tất cả những gì bạn cần.

2

Django-model-values (tiết lộ: tác giả) cung cấp triển khai tra cứu NotEqual, như trong this answer. Nó cũng cung cấp hỗ trợ cú pháp cho nó:

from model_values import F 
Model.objects.exclude(F.x != 5, a=True) 
Các vấn đề liên quan