Sự khác biệt giữa bộ lọc với nhiều đối số và bộ lọc chuỗi trong django là gì?
Sự khác biệt giữa bộ lọc với nhiều đối số và bộ lọc chuỗi trong django là gì?
Câu trả lời:
Như bạn có thể thấy trong các câu lệnh SQL được tạo, sự khác biệt không phải là "OR" như một số người có thể nghi ngờ. Đó là cách đặt WHERE và JOIN.
Ví dụ1 (cùng một bảng được kết hợp): từ https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Blog.objects.filter(
entry__headline__contains='Lennon',
entry__pub_date__year=2008)
Điều này sẽ cung cấp cho bạn tất cả các Blog có một mục nhập với cả hai (entry__headline__contains='Lennon') AND (entry__pub_date__year=2008)
, đó là những gì bạn mong đợi từ truy vấn này.
Kết quả:
Blog with {entry.headline: 'Life of Lennon', entry.pub_date: '2008'}
Ví dụ 2 (chuỗi)
Blog.objects.filter(
entry__headline__contains='Lennon'
).filter(
entry__pub_date__year=2008)
Điều này sẽ bao gồm tất cả các kết quả từ Ví dụ 1, nhưng nó sẽ tạo ra nhiều kết quả hơn một chút. Bởi vì trước tiên nó lọc tất cả các blog có (entry__headline__contains='Lennon')
và sau đó từ các bộ lọc kết quả (entry__pub_date__year=2008)
.
Sự khác biệt là nó cũng sẽ cho bạn kết quả như:
Một Blog có nhiều mục
{entry.headline: '**Lennon**', entry.pub_date: 2000},
{entry.headline: 'Bill', entry.pub_date: **2008**}
Khi bộ lọc đầu tiên được đánh giá, sách được bao gồm vì mục nhập đầu tiên (mặc dù sách có các mục nhập khác không khớp). Khi bộ lọc thứ hai được đánh giá, sách được bao gồm vì mục nhập thứ hai.
Một bảng: Nhưng nếu truy vấn không liên quan đến các bảng đã kết hợp như ví dụ từ Yuji và DTing. Kết quả là như nhau.
(entry__headline__contains='Lennon')
và sau đó từ kết quả lọc (entry__pub_date__year=2008)
" Nếu "thì từ kết quả" là chính xác, tại sao nó sẽ bao gồm một cái gì đó với entry.headline == 'Bill'
.. .sẽ không entry__headline__contains='Lennon'
lọc ra Bill
trường hợp?
Trường hợp kết quả của "nhiều đối số bộ lọc-truy vấn" khác với "chuỗi-bộ lọc-truy vấn", như sau:
Lựa chọn đối tượng được tham chiếu trên cơ sở đối tượng tham chiếu và mối quan hệ là một-nhiều (hoặc nhiều-nhiều).
Nhiều bộ lọc:
Referenced.filter(referencing1_a=x, referencing1_b=y) # same referencing model ^^ ^^
Bộ lọc chuỗi:
Referenced.filter(referencing1_a=x).filter(referencing1_b=y)
Cả hai truy vấn có thể xuất ra kết quả khác nhau:
Nếu nhiều hơn thì một hàng trong mô hìnhReferencing1
tham chiếu có thể tham chiếu đến cùng một hàng trong mô hình được tham chiếuReferenced
. Điều này có thể xảy ra trongReferenced
:Referencing1
có 1: N (một đến nhiều) hoặc N: M (nhiều đến nhiều)-ship.
Thí dụ:
Hãy xem xét ứng dụng của tôi my_company
có hai mô hình Employee
và Dependent
. Một nhân viên trong my_company
có thể có nhiều hơn người phụ thuộc (nói cách khác, một người phụ thuộc có thể là con trai / con gái của một nhân viên duy nhất, trong khi một nhân viên có thể có nhiều hơn một con trai / con gái).
Ơ, giả sử như vợ chồng cả hai đều không thể làm việc a my_company
. Tôi lấy ví dụ 1: m
Vì vậy, Employee
là mô hình tham chiếu có thể được tham chiếu bởi nhiều hơn thì Dependent
đó là mô hình tham chiếu. Bây giờ hãy xem xét trạng thái quan hệ như sau:
Employee: Dependent: +------+ +------+--------+-------------+--------------+ | name | | name | E-name | school_mark | college_mark | +------+ +------+--------+-------------+--------------+ | A | | a1 | A | 79 | 81 | | B | | b1 | B | 80 | 60 | +------+ | b2 | B | 68 | 86 | +------+--------+-------------+--------------+
Phụ thuộc
a1
đề cập đến nhân viênA
, và phụ thuộcb1, b2
đề cập đến nhân viênB
.
Bây giờ truy vấn của tôi là:
Tìm tất cả nhân viên có con trai / con gái có điểm phân biệt (giả sử> = 75%) ở cả trường đại học và trường học?
>>> Employee.objects.filter(dependent__school_mark__gte=75,
... dependent__college_mark__gte=75)
[<Employee: A>]
Đầu ra là 'A' phụ thuộc 'a1' có điểm phân biệt ở cả trường đại học và trường học phụ thuộc vào nhân viên 'A'. Lưu ý 'B' không được chọn vì em của 'B' có điểm phân biệt ở cả trường đại học và trường học. Đại số quan hệ:
Nhân viên ⋈ (school_mark> = 75 AND college_mark> = 75) Phụ thuộc
Trong trường hợp thứ hai, tôi cần một truy vấn:
Tìm tất cả nhân viên có một số người phụ thuộc có điểm khác biệt trong trường đại học và trường học?
>>> Employee.objects.filter(
... dependent__school_mark__gte=75
... ).filter(
... dependent__college_mark__gte=75)
[<Employee: A>, <Employee: B>]
Lần này "B" cũng được chọn vì "B" có hai đứa con (nhiều hơn một!), Một đứa có điểm phân biệt ở trường "b1" và đứa còn lại có điểm phân biệt ở trường đại học "b2".
Thứ tự của bộ lọc không quan trọng, chúng tôi cũng có thể viết truy vấn ở trên là:
>>> Employee.objects.filter(
... dependent__college_mark__gte=75
... ).filter(
... dependent__school_mark__gte=75)
[<Employee: A>, <Employee: B>]
kết quả là như nhau! Đại số quan hệ có thể là:
(Nhân viên ⋈ (điểm trường> = 75) Phụ thuộc) ⋈ (dấu đại học> = 75) Phụ thuộc
Lưu ý sau:
dq1 = Dependent.objects.filter(college_mark__gte=75, school_mark__gte=75)
dq2 = Dependent.objects.filter(college_mark__gte=75).filter(school_mark__gte=75)
Kết quả tương tự: [<Dependent: a1>]
Tôi kiểm tra truy vấn SQL mục tiêu được tạo bởi Django bằng cách sử dụng print qd1.query
và print qd2.query
cả hai đều giống nhau (Django 1.6).
Nhưng về mặt ngữ nghĩa cả hai đều khác nhau đối với tôi . đầu tiên trông giống như phần đơn giản σ [school_mark> = 75 VÀ college_mark> = 75] (Phụ thuộc) và thứ hai giống như truy vấn lồng nhau chậm: σ [school_mark> = 75] (σ [college_mark> = 75] (Phụ thuộc)).
Nếu ai đó cần Mã @codepad
btw, nó được đưa ra trong tài liệu @ Kéo dài các mối quan hệ đa giá trị Tôi vừa thêm một ví dụ, tôi nghĩ nó sẽ hữu ích cho người mới.
Hầu hết thời gian, chỉ có một bộ kết quả khả thi cho một truy vấn.
Việc sử dụng cho các bộ lọc chuỗi khi bạn xử lý m2m:
Xem xét điều này:
# will return all Model with m2m field 1
Model.objects.filter(m2m_field=1)
# will return Model with both 1 AND 2
Model.objects.filter(m2m_field=1).filter(m2m_field=2)
# this will NOT work
Model.objects.filter(Q(m2m_field=1) & Q(m2m_field=2))
Các ví dụ khác được hoan nghênh.
Sự khác biệt về hiệu suất là rất lớn. Hãy thử nó và xem.
Model.objects.filter(condition_a).filter(condition_b).filter(condition_c)
chậm một cách đáng ngạc nhiên so với
Model.objects.filter(condition_a, condition_b, condition_c)
Như đã đề cập trong ORM Django hiệu quả ,
- QuerySets duy trì trạng thái trong bộ nhớ
- Chuỗi kích hoạt nhân bản, sao chép trạng thái đó
- Thật không may, QuerySets duy trì rất nhiều trạng thái
- Nếu có thể, không chuỗi nhiều hơn một bộ lọc
Bạn có thể sử dụng mô-đun kết nối để xem các truy vấn sql thô để so sánh. Theo giải thích của Yuji, phần lớn chúng tương đương nhau như được hiển thị ở đây:
>>> from django.db import connection
>>> samples1 = Unit.objects.filter(color="orange", volume=None)
>>> samples2 = Unit.objects.filter(color="orange").filter(volume=None)
>>> list(samples1)
[]
>>> list(samples2)
[]
>>> for q in connection.queries:
... print q['sql']
...
SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL)
SELECT `samples_unit`.`id`, `samples_unit`.`color`, `samples_unit`.`volume` FROM `samples_unit` WHERE (`samples_unit`.`color` = orange AND `samples_unit`.`volume` IS NULL)
>>>
Nếu bạn kết thúc trên trang này tìm cách để tự động xây dựng một django queryset với nhiều bộ lọc loạt, nhưng bạn cần các bộ lọc để có những AND
loại thay vì OR
, hãy xem xét sử dụng đối tượng Q .
Một ví dụ:
# First filter by type.
filters = None
if param in CARS:
objects = app.models.Car.objects
filters = Q(tire=param)
elif param in PLANES:
objects = app.models.Plane.objects
filters = Q(wing=param)
# Now filter by location.
if location == 'France':
filters = filters & Q(quay=location)
elif location == 'England':
filters = filters & Q(harbor=location)
# Finally, generate the actual queryset
queryset = objects.filter(filters)
Nếu yêu cầu a và b thì
and_query_set = Model.objects.filter(a=a, b=b)
nếu yêu cầu a cũng như b thì
chaied_query_set = Model.objects.filter(a=a).filter(b=b)
Tài liệu chính thức: https://docs.djangoproject.com/en/dev/topics/db/queries/#spanning-multi-valued-relationships
Bài viết liên quan: Chuỗi nhiều bộ lọc () trong Django, đây có phải là một lỗi?
Có một sự khác biệt khi bạn có yêu cầu đối với đối tượng liên quan của mình, chẳng hạn
class Book(models.Model):
author = models.ForeignKey(Author)
name = models.ForeignKey(Region)
class Author(models.Model):
name = models.ForeignKey(Region)
yêu cầu
Author.objects.filter(book_name='name1',book_name='name2')
trả về tập hợp trống
và yêu cầu
Author.objects.filter(book_name='name1').filter(book_name='name2')
trả về các tác giả có sách có cả 'name1' và 'name2'
để biết chi tiết, hãy xem https://docs.djangoproject.com/en/dev/topics/db/queries/#s-spanning-multi-valued-relationships
Author.objects.filter(book_name='name1',book_name='name2')
thậm chí không phải là python hợp lệ, nó sẽ làSyntaxError: keyword argument repeated