Skip to content

Commit 2feab3b

Browse files
committed
temp2
1 parent 74a16c2 commit 2feab3b

1 file changed

Lines changed: 15 additions & 14 deletions

File tree

pulpcore/app/util.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,15 +26,13 @@
2626
from pulpcore.app.loggers import deprecation_logger
2727
from pulpcore.exceptions.validation import InvalidSignatureError
2828

29-
POSTGRES_MAX_QUERY_PARAMS = 65535
30-
3129

3230
class AnyArray(Lookup):
33-
"""PostgreSQL `= ANY(%s)` lookup that passes a list as a single array parameter.
31+
"""PostgreSQL ``= ANY(%s)`` lookup that passes a list as a single array parameter.
3432
3533
psycopg3 adapts the Python list into a PostgreSQL array, so the entire list
3634
counts as **one** bind parameter regardless of size. This avoids the
37-
protocol-level 65535-parameter limit that `IN ($1, $2, …)` hits.
35+
protocol-level 65,535-parameter limit that ``IN ($1, $2, …)`` hits.
3836
"""
3937

4038
lookup_name = "any_array"
@@ -51,20 +49,23 @@ def as_sql(self, compiler, connection):
5149

5250

5351
def safe_in(field_name, values):
54-
"""Build a `Q` object for `field__in` that is safe for arbitrarily large lists.
52+
"""Build a ``Q`` object for filtering by a list of values that is safe at any size.
53+
54+
Uses PostgreSQL's ``= ANY(array)`` syntax so the entire list is sent as a
55+
single bind parameter, avoiding the 65,535-parameter protocol limit that
56+
Django's default ``__in`` lookup hits with large lists.
5557
56-
* If *values* is already a queryset (or other non-collection type), the
57-
normal `__in` lookup is used — Django turns it into a subquery.
58-
* If the collection has fewer than 65 535 items, `__in` is used as-is.
59-
* Otherwise `__any_array` is used so the whole list travels as a single
60-
PostgreSQL array parameter.
58+
Use this for values that are **already materialised in Python** (e.g.
59+
parsed from JSON, accumulated in a loop). When the IDs live in a database
60+
column, prefer a subquery instead — it keeps the data server-side and
61+
avoids the round-trip entirely.
62+
63+
If *values* is a queryset (or other non-collection type), falls back to
64+
the normal ``__in`` lookup, which Django turns into a subquery.
6165
"""
6266
if not isinstance(values, (list, set, tuple, frozenset)):
6367
return Q(**{f"{field_name}__in": values})
64-
values = list(values)
65-
if len(values) < POSTGRES_MAX_QUERY_PARAMS:
66-
return Q(**{f"{field_name}__in": values})
67-
return Q(**{f"{field_name}__any_array": values})
68+
return Q(**{f"{field_name}__any_array": list(values)})
6869

6970

7071
# a little cache so viewset_for_model doesn't have to iterate over every app every time

0 commit comments

Comments
 (0)