From 476e5def5fcbcf637945985a23675db0e1f59354 Mon Sep 17 00:00:00 2001 From: Tim Graham Date: Mon, 9 Mar 2026 16:45:50 -0400 Subject: [PATCH] Refactored PatternLookup to improve readability. --- django/db/models/lookups.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py index eaf3d69a5967..4c08999fb6df 100644 --- a/django/db/models/lookups.py +++ b/django/db/models/lookups.py @@ -578,32 +578,41 @@ class PatternLookup(BuiltinLookup): prepare_rhs = False def get_rhs_op(self, connection, rhs): - # Assume we are in startswith. We need to produce SQL like: - # col LIKE %s, ['thevalue%'] - # For python values we can (and should) do that directly in Python, - # but if the value is for example reference to other column, then - # we need to add the % pattern match to the lookup by something like + # If the lookup value is a reference to another column or a transform, + # then the SQL is something like: # col LIKE othercol || '%%' - # So, for Python values we don't need any special pattern, but for - # SQL reference values or SQL transformations we need the correct - # pattern added. - if hasattr(self.rhs, "as_sql") or self.bilateral_transforms: + if not self.is_simple_lookup: + # In that case, prepare the LIKE clause using + # DatabaseWrapper.pattern_ops. pattern = connection.pattern_ops[self.lookup_name].format( connection.pattern_esc ) return pattern.format(rhs) else: + # Otherwise, use the LIKE in DatabaseWrapper.operators. return super().get_rhs_op(connection, rhs) def process_rhs(self, qn, connection): rhs, params = super().process_rhs(qn, connection) - if self.rhs_is_direct_value() and params and not self.bilateral_transforms: + # Assume the lookup is startswith. For simple lookups involving a + # Python value like "thevalue", the (SQL, params) is something like: + # ("col LIKE %s", ['thevalue%']) + if self.is_simple_lookup: + # Prepare the lookup parameter, a Python value, for use in a LIKE + # clause, usually by adding % signs to the beginning and/or end of + # the value. param = connection.ops.prep_for_like_query(params[0]) if connection.features.pattern_lookup_needs_param_pattern: param = self.param_pattern % param params = (param, *params[1:]) return rhs, params + @property + def is_simple_lookup(self): + # A "simple lookup" is a Python value (as long as it's not a bilateral + # transform). + return self.rhs_is_direct_value() and not self.bilateral_transforms + @Field.register_lookup class Contains(PatternLookup):