"&" и "|" против "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":

enter image description here

И, при выполнении кода 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 как показано ниже:

enter image description here

Вернуться на верх