"&" и "|" против "and" и "or" для операторов "AND" и "OR" в Django
У меня есть Blog
модель ниже. * Я использую Django 3.2.16 и PostgreSQL:
# "store/models.py"
from django.db import models
class Blog(models.Model):
post = models.TextField()
def __str__(self):
return self.post
Тогда, store_blog
таблица имеет 2 строки ниже:
store_blog
таблица:
id | post |
---|---|
1 | Python is popular and simple. |
2 | Java is popular and complex. |
Тогда, при выполнении кода filter() с использованием &
или Q() и &
. или используя and
или Q()
и and
в test()
представлении, как показано ниже:
# "store/views.py"
from .models import Blog
from django.db.models import Q
def test(request):
# With "&"
# ↓ Here
qs = Blog.objects.filter(post__contains="popular") & \
Blog.objects.filter(post__contains="simple")
print(qs)
# With "Q()" and "&"
# ↓ Here # ↓ Here
qs = Blog.objects.filter(Q(post__contains="popular") &
Q(post__contains="simple"))
print(qs) # ↑ Here
# With "and"
# ↓ Here
qs = Blog.objects.filter(post__contains="popular") and \
Blog.objects.filter(post__contains="simple")
print(qs)
# With "Q()" and "and"
# ↓ Here # ↓ Here
qs = Blog.objects.filter(Q(post__contains="popular") and
Q(post__contains="simple"))
print(qs) # ↑ Here
return HttpResponse("Test")
Я получил тот же результат, что и ниже:
<QuerySet [<Blog: Python is popular and simple.>]> # With "&"
<QuerySet [<Blog: Python is popular and simple.>]> # With "Q()" and "&"
<QuerySet [<Blog: Python is popular and simple.>]> # With "and"
<QuerySet [<Blog: Python is popular and simple.>]> # With "Q()" and "and"
[22/Dec/2022 16:04:45] "GET /store/test/ HTTP/1.1" 200 9
И, при выполнении кода filter()
с использованием |
или Q()
и |
или используя or
или Q()
и or
в test()
представлении, как показано ниже:
# "store/views.py"
from .models import Blog
from django.db.models import Q
def test(request):
# With "|"
# ↓ Here
qs = Blog.objects.filter(post__contains="popular") | \
Blog.objects.filter(post__contains="simple")
print(qs)
# With "Q()" and "|"
# ↓ Here # ↓ Here
qs = Blog.objects.filter(Q(post__contains="popular") |
Q(post__contains="simple"))
print(qs) # ↑ Here
# With "or"
# ↓ Here
qs = Blog.objects.filter(post__contains="popular") or \
Blog.objects.filter(post__contains="simple")
print(qs)
# With "Q()" and "or"
# ↓ Here # ↓ Here
qs = Blog.objects.filter(Q(post__contains="popular") or
Q(post__contains="simple"))
print(qs) # ↑ Here
return HttpResponse("Test")
Я получил тот же результат, что и ниже:
<QuerySet [<Blog: Python is popular and simple.>, <Blog: Java is popular and complex.>]> # With "|"
<QuerySet [<Blog: Python is popular and simple.>, <Blog: Java is popular and complex.>]> # With "Q()" and "|"
<QuerySet [<Blog: Python is popular and simple.>, <Blog: Java is popular and complex.>]> # With "or"
<QuerySet [<Blog: Python is popular and simple.>, <Blog: Java is popular and complex.>]> # With "Q()" and "or"
[22/Dec/2022 16:20:27] "GET /store/test/ HTTP/1.1" 200 9
Итак, есть ли различия между &
и and
и |
и or
для AND
и OR
операторов в Django?
Ваши тестовые данные совершенно недостаточны для этого теста, поскольку обе строки содержат popular
. (То есть, все, что может найти popular
, эквивалентно Blog.objects.all()
.)
В любом случае, булевы or
и and
здесь работают неправильно (поскольку они просто выполняют булеву оценку), но вы просто не замечаете этого из-за вышеизложенного.
Вам необходимо использовать операторы "bitwise" |
/ &
/ ^
, как указано в документации. ("bitwise" в кавычках, так как класс Q
перегружает операторы, чтобы они не были bitwise вообще.)
Для доказательства рассмотрим Q
изолированно, ничего не запрашивая...
>>> from django.db.models import Q
>>> pop = Q(post__contains="popular")
<Q: (AND: ('post__contains', 'popular'))>
>>> sim = Q(post__contains="simple")
<Q: (AND: ('post__contains', 'simple'))>
>>> pop and sim
<Q: (AND: ('post__contains', 'simple'))>
# ^ incorrect; evaluates to `sim`
>>> pop & sim
<Q: (AND: ('post__contains', 'popular'), ('post__contains', 'simple'))>
# ^ correct: combines the two q:s with `and`
>>> pop or sim
<Q: (AND: ('post__contains', 'popular'))>
# ^ incorrect; evaluates to `pop`
>>> pop | sim
<Q: (OR: ('post__contains', 'popular'), ('post__contains', 'simple'))>
# ^ correct: combines the two q:s with `or`
При выполнении кода filter()
с использованием &
или Q()
и &
или используя and
или Q()
и and
в test()
представлении, как показано ниже:
# "store/views.py"
from .models import Blog
from django.db.models import Q
from django.http import HttpResponse
def test(request):
# With "&"
# ↓ Here
qs = Blog.objects.filter(post__contains="popular") & \
Blog.objects.filter(post__contains="simple")
print(qs)
# With "Q()" and "&"
# ↓ Here # ↓ Here
qs = Blog.objects.filter(Q(post__contains="popular") &
Q(post__contains="simple"))
print(qs) # ↑ Here
# With "and"
# ↓ Here
qs = Blog.objects.filter(post__contains="popular") and \
Blog.objects.filter(post__contains="simple")
print(qs)
# With "Q()" and "and"
# ↓ Here # ↓ Here
qs = Blog.objects.filter(Q(post__contains="popular") and
Q(post__contains="simple"))
print(qs) # ↑ Here
return HttpResponse("Test")
&
или Q()
и &
могут выполнять AND
операторы в соответствии с журналами запросов PostgreSQL, как показано ниже. *Вы можете проверить на PostgreSQL, как регистрировать запросы с транзакционными запросами, такими как "BEGIN" и "COMMIT":
И, при выполнении кода filter()
с использованием |
или Q()
и |
или используя or
или Q()
и or
в test()
представлении, как показано ниже:
# "store/views.py"
from .models import Blog
from django.db.models import Q
from django.http import HttpResponse
def test(request):
# With "|"
# ↓ Here
qs = Blog.objects.filter(post__contains="popular") | \
Blog.objects.filter(post__contains="simple")
print(qs)
# With "Q()" and "|"
# ↓ Here # ↓ Here
qs = Blog.objects.filter(Q(post__contains="popular") |
Q(post__contains="simple"))
print(qs) # ↑ Here
# With "or"
# ↓ Here
qs = Blog.objects.filter(post__contains="popular") or \
Blog.objects.filter(post__contains="simple")
print(qs)
# With "Q()" and "or"
# ↓ Here # ↓ Here
qs = Blog.objects.filter(Q(post__contains="popular") or
Q(post__contains="simple"))
print(qs) # ↑ Here
return HttpResponse("Test")
|
или Q()
и |
могут выполнять OR
операторы согласно журналам запросов PostgreSQL как показано ниже: