"&" и "|" против "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 как показано ниже:

