Lọc các tên trống hoặc NULL trong bộ truy vấn


463

Tôi có first_name, last_name& alias(tùy chọn) mà tôi cần tìm kiếm. Vì vậy, tôi cần một truy vấn để cung cấp cho tôi tất cả các tên có bộ bí danh.

Chỉ khi tôi có thể làm:

Name.objects.filter(alias!="")

Vậy, những gì tương đương với ở trên?

Câu trả lời:


840

Bạn có thể làm điều này:

Name.objects.exclude(alias__isnull=True)

Nếu bạn cần loại trừ các giá trị null chuỗi rỗng, cách ưa thích để làm như vậy là xâu chuỗi các điều kiện như sau:

Name.objects.exclude(alias__isnull=True).exclude(alias__exact='')

Xâu chuỗi các phương thức này với nhau về cơ bản kiểm tra từng điều kiện một cách độc lập: trong ví dụ trên, chúng tôi loại trừ các hàng aliascó giá trị null hoặc chuỗi rỗng, do đó bạn nhận được tất cả Namecác đối tượng có trường không rỗng, không trống alias. SQL được tạo sẽ trông giống như:

SELECT * FROM Name WHERE alias IS NOT NULL AND alias != ""

Bạn cũng có thể chuyển nhiều đối số cho một cuộc gọi đến exclude, điều này sẽ đảm bảo rằng chỉ các đối tượng đáp ứng mọi điều kiện bị loại trừ:

Name.objects.exclude(some_field=True, other_field=True)

Ở đây, các hàng trong đó some_field other_field đúng được loại trừ, vì vậy chúng tôi nhận được tất cả các hàng trong đó cả hai trường đều không đúng. Mã SQL được tạo sẽ trông giống như thế này:

SELECT * FROM Name WHERE NOT (some_field = TRUE AND other_field = TRUE)

Ngoài ra, nếu logic của bạn phức tạp hơn thế, bạn có thể sử dụng các đối tượng Q của Django :

from django.db.models import Q
Name.objects.exclude(Q(alias__isnull=True) | Q(alias__exact=''))

Để biết thêm thông tin xem trang nàytrang này trong tài liệu Django.

Bên cạnh: Các ví dụ SQL của tôi chỉ là một sự tương tự - mã SQL được tạo thực tế có thể sẽ trông khác nhau. Bạn sẽ hiểu sâu hơn về cách các truy vấn Django hoạt động bằng cách thực sự nhìn vào SQL mà chúng tạo ra.


5
Tôi tin rằng chỉnh sửa của bạn là sai: Bộ lọc chuỗi KHÔNG tự động tạo SQL OR(chỉ trong trường hợp này), nó tạo ra SQL AND. Xem trang này để tham khảo: docs.djangoproject.com/en/dev/topics/db/queries/ Khăn Ưu điểm của chuỗi là bạn có thể trộn excludefiltermô hình hóa các điều kiện truy vấn phức tạp. Nếu bạn muốn mô hình hóa một SQL thực, ORbạn phải sử dụng một đối tượng Django Q: docs.djangoproject.com/en/dev/topics/db/queries/, Vui lòng chỉnh sửa chỉnh sửa của bạn để phản ánh điều này, vì câu trả lời bị sai lệch nghiêm trọng .
shezi

1
@shezi: Tôi muốn nói nó giống như một sự tương tự - Tôi không có nghĩa là mã SQL thực tế được đảm bảo sử dụng ORđể hợp nhất các điều kiện. Tôi sẽ chỉnh sửa câu trả lời của tôi để làm rõ.
Sasha Chedygov

1
Hãy nhớ rằng có nhiều cách khác nhau để biểu diễn logic này - ví dụ, NOT (A AND B)tương đương với NOT A OR NOT B. Tôi nghĩ rằng điều đó làm cho mọi thứ trở nên khó hiểu đối với các nhà phát triển Django mới biết SQL nhưng không quen thuộc với ORM.
Sasha Chedygov

3
Tôi biết luật của De Morgan và đây chính xác là quan điểm của tôi: Ví dụ của bạn chỉ hoạt động vì lợi dụng để biến ANDtruy vấn đầu tiên thành ORvì bạn đang sử dụng exclude. Trong trường hợp chung, có lẽ đúng hơn khi nghĩ về chuỗi như một THEN, tức là exclude(A) THEN exclude(B). Xin lỗi về ngôn ngữ khắc nghiệt ở trên. Câu trả lời của bạn thực sự tốt, nhưng tôi lo lắng về việc các nhà phát triển mới nhận câu trả lời của bạn quá chung chung.
shezi

2
@shezi: Đủ công bằng. Tôi đồng ý rằng tốt hơn là nghĩ về thuật ngữ Django chứ không phải bằng thuật ngữ SQL, tôi chỉ nghĩ rằng trình bày chuỗi theo thuật ngữ ANDORcó thể hữu ích cho ai đó đến Django từ nền tảng SQL. Để hiểu sâu hơn về Django, tôi nghĩ rằng các tài liệu làm một công việc tốt hơn tôi có thể.
Sasha Chedygov

49
Name.objects.filter(alias__gt='',alias__isnull=False)

2
Tôi không chắc chắn, nhưng tôi nghĩ rằng alias__isnull=Falseđiều kiện là dư thừa. Nếu lĩnh vực Nullchắc chắn nó sẽ bị loại trừ bởi mệnh đề đầu tiên?
Bobble

Ngoài nhận xét / câu hỏi trước đây của tôi, tôi nghĩ rằng logic tích cực ở đây dễ theo dõi hơn trong một số câu trả lời khác.
Bobble

@Bobble sẽ phụ thuộc vào việc triển khai cơ sở dữ liệu - việc đặt hàng được ủy quyền cho
wpercy

alias__gtlà điều duy nhất hoạt động cho các cột kiểu JSON nơi tôi muốn loại trừ các chuỗi rỗng khỏi JSON như thế nào {'something:''}. Vì vậy, cú pháp làm việc là:jsoncolumnname__something__gt=''
bartgras

38

Đầu tiên, các tài liệu Django khuyên bạn không nên sử dụng các giá trị NULL cho các trường dựa trên chuỗi như CharField hoặc TextField. Đọc tài liệu để được giải thích:

https://docs.djangoproject.com/en/dev/ref/models/fields/#null

Giải pháp: Tôi cũng có thể xâu chuỗi các phương thức lại với nhau trên QuerySets. Thử cái này:

Name.objects.exclude(alias__isnull=True).exclude(alias="")

Điều đó sẽ cung cấp cho bạn các thiết lập bạn đang tìm kiếm.


5

Từ Django 1.8,

from django.db.models.functions import Length

Name.objects.annotate(alias_length=Length('alias')).filter(alias_length__gt=0)

5
Điều này có vẻ giống như "một việc bạn có thể làm", không phải là việc bạn nên làm. Nó làm tăng đáng kể độ phức tạp truy vấn qua hai kiểm tra đơn giản.
Oli

3

Để tránh những lỗi phổ biến khi sử dụng exclude, hãy nhớ:

Bạn không thể thêm nhiều điều kiện vào một khối loại trừ () như thế nào filter. Để loại trừ nhiều điều kiện, bạn phải sử dụng nhiều loại trừ ()

Thí dụ

Không chính xác :

User.objects.filter (email='example@example.com '). Loại trừ (profile__nick_name =' ', profile__avt =' ')

Đúng :

User.objects.filter (email='example@example.com '). Loại trừ (profile__nick_name =' '). Loại trừ (profile__avt =' ')


0

Bạn chỉ có thể làm điều này:

Name.objects.exclude(alias="").exclude(alias=None)

Nó thực sự chỉ đơn giản như vậy. filterđược sử dụng để khớp và excludephù hợp với mọi thứ nhưng những gì nó chỉ định. Điều này sẽ đánh giá thành SQL như NOT alias='' AND alias IS NOT NULL.


Điều này là không chính xác. Câu hỏi nhằm loại trừ các bí danh rỗng ( alias="") và NULL ( alias=None) khỏi truy vấn. Bạn sẽ bao gồm các trường hợp với Name(alias=None).
damon

@damon - Tôi đã trả lời những gì tương đương .filter(alias!="")nhưng không phải tiêu đề. Tôi đã chỉnh sửa câu trả lời của mình. Tuy nhiên, các trường ký tự không nên cho phép các giá trị NULL và sử dụng chuỗi trống cho một giá trị không (theo quy ước).
Tim Tonomall

-1

đây là một cách đơn giản để làm điều đó

Name.objects.exclude(alias=None)

Nonekhông phải là điều tương tự như "".
Tim Tonomall
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.