mirror of
https://github.com/django/django.git
synced 2025-11-17 02:24:22 +00:00
Preserve input iterable type in resolve_lookup_value
Fix regression where list inputs were coerced to tuples in Query.resolve_lookup_value, breaking exact value queries for fields sensitive to input type (e.g., PickledField). Adds tests to ensure input type is preserved. Refs #30687.
This commit is contained in:
parent
b93a0e34d9
commit
e10a37076b
2 changed files with 43 additions and 2 deletions
|
|
@ -1073,7 +1073,8 @@ class Query(BaseExpression):
|
|||
))
|
||||
else:
|
||||
resolved_values.append(sub_value)
|
||||
value = tuple(resolved_values)
|
||||
# Preserve the type of the input iterable (list or tuple).
|
||||
value = type(value)(resolved_values)
|
||||
return value
|
||||
|
||||
def solve_lookup_type(self, lookup):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ from datetime import datetime
|
|||
|
||||
from django.core.exceptions import FieldError
|
||||
from django.db.models import CharField, F, Q
|
||||
from django.db.models.expressions import SimpleCol
|
||||
from django.db.models.expressions import Col, SimpleCol
|
||||
from django.db.models.fields.related_lookups import RelatedIsNull
|
||||
from django.db.models.functions import Lower
|
||||
from django.db.models.lookups import Exact, GreaterThan, IsNull, LessThan
|
||||
|
|
@ -113,3 +113,43 @@ class TestQuery(SimpleTestCase):
|
|||
clone = query.clone()
|
||||
clone.add_select_related(['note', 'creator__extra'])
|
||||
self.assertEqual(query.select_related, {'creator': {}})
|
||||
|
||||
def test_resolve_lookup_value_preserves_list_type(self):
|
||||
"""
|
||||
resolve_lookup_value() should preserve the type of list/tuple inputs.
|
||||
This is important for field lookups that depend on exact type matching
|
||||
(e.g., PickledField).
|
||||
Regression test for issue where resolve_lookup_value() was converting
|
||||
all iterables to tuples, breaking exact value queries for fields that
|
||||
depend on matching input types.
|
||||
"""
|
||||
query = Query(Author)
|
||||
# Test that list input returns list output
|
||||
list_value = [1, 2, 3]
|
||||
resolved = query.resolve_lookup_value(list_value, can_reuse=None, allow_joins=True, simple_col=False)
|
||||
self.assertIsInstance(resolved, list)
|
||||
self.assertEqual(resolved, [1, 2, 3])
|
||||
|
||||
# Test that tuple input returns tuple output
|
||||
tuple_value = (1, 2, 3)
|
||||
resolved = query.resolve_lookup_value(tuple_value, can_reuse=None, allow_joins=True, simple_col=False)
|
||||
self.assertIsInstance(resolved, tuple)
|
||||
self.assertEqual(resolved, (1, 2, 3))
|
||||
|
||||
# Test with expressions in list
|
||||
list_with_f = [F('num'), 2, 3]
|
||||
resolved = query.resolve_lookup_value(list_with_f, can_reuse=None, allow_joins=True, simple_col=False)
|
||||
self.assertIsInstance(resolved, list)
|
||||
self.assertEqual(len(resolved), 3)
|
||||
self.assertIsInstance(resolved[0], Col)
|
||||
self.assertEqual(resolved[1], 2)
|
||||
self.assertEqual(resolved[2], 3)
|
||||
|
||||
# Test with expressions in tuple
|
||||
tuple_with_f = (F('num'), 2, 3)
|
||||
resolved = query.resolve_lookup_value(tuple_with_f, can_reuse=None, allow_joins=True, simple_col=False)
|
||||
self.assertIsInstance(resolved, tuple)
|
||||
self.assertEqual(len(resolved), 3)
|
||||
self.assertIsInstance(resolved[0], Col)
|
||||
self.assertEqual(resolved[1], 2)
|
||||
self.assertEqual(resolved[2], 3)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue