Refs #30581 -- Added Q.flatten().

This commit is contained in:
Gagaro 2022-05-03 14:06:42 +02:00 committed by Mariusz Felisiak
parent df22566748
commit 9d04711261
2 changed files with 42 additions and 1 deletions

View File

@ -95,6 +95,21 @@ class Q(tree.Node):
query.promote_joins(joins)
return clause
def flatten(self):
"""
Recursively yield this Q object and all subexpressions, in depth-first
order.
"""
yield self
for child in self.children:
if isinstance(child, tuple):
# Use the lookup.
child = child[1]
if hasattr(child, "flatten"):
yield from child.flatten()
else:
yield child
def deconstruct(self):
path = "%s.%s" % (self.__class__.__module__, self.__class__.__name__)
if path.startswith("django.db.models.query_utils"):

View File

@ -1,5 +1,15 @@
from django.db.models import BooleanField, Exists, F, OuterRef, Q
from django.db.models import (
BooleanField,
Exists,
ExpressionWrapper,
F,
OuterRef,
Q,
Value,
)
from django.db.models.expressions import RawSQL
from django.db.models.functions import Lower
from django.db.models.sql.where import NothingNode
from django.test import SimpleTestCase
from .models import Tag
@ -188,3 +198,19 @@ class QTests(SimpleTestCase):
q = q1 & q2
path, args, kwargs = q.deconstruct()
self.assertEqual(Q(*args, **kwargs), q)
def test_flatten(self):
q = Q()
self.assertEqual(list(q.flatten()), [q])
q = Q(NothingNode())
self.assertEqual(list(q.flatten()), [q, q.children[0]])
q = Q(
ExpressionWrapper(
Q(RawSQL("id = 0", params=(), output_field=BooleanField()))
| Q(price=Value("4.55"))
| Q(name=Lower("category")),
output_field=BooleanField(),
)
)
flatten = list(q.flatten())
self.assertEqual(len(flatten), 7)