#30826 closed Bug (fixed)
Chaining __contains lookup with JSONField key transforms crashes.
Reported by: | Nic Perry | Owned by: | Louise Grandjonc |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 1.11 |
Severity: | Release blocker | Keywords: | JSONField, contains |
Cc: | Simon Charette, Massimo Costa, Shaheed Haque | Triage Stage: | Ready for checkin |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Consider a model that looks like this:
class Event(models.Model): data = JSONField(default=dict)
Create an instance of this model with a nested array:
data = { "things": ["thing1", "thing2", "thing3"] } Event.objects.create(data=data)
The following lookup works in 1.11.24, but returns an error (traceback below) in 1.11.25:
Event.objects.filter(data__things__contains="thing1")
1.11.25 Traceback:
TypeError Traceback (most recent call last) /usr/lib/python3.7/site-packages/django/db/models/query.py in __repr__(self) 224 225 def __repr__(self): --> 226 data = list(self[:REPR_OUTPUT_SIZE + 1]) 227 if len(data) > REPR_OUTPUT_SIZE: 228 data[-1] = "...(remaining elements truncated)..." /usr/lib/python3.7/site-packages/django/db/models/query.py in __iter__(self) 248 - Responsible for turning the rows into model objects. 249 """ --> 250 self._fetch_all() 251 return iter(self._result_cache) 252 /usr/lib/python3.7/site-packages/django/db/models/query.py in _fetch_all(self) 1119 def _fetch_all(self): 1120 if self._result_cache is None: -> 1121 self._result_cache = list(self._iterable_class(self)) 1122 if self._prefetch_related_lookups and not self._prefetch_done: 1123 self._prefetch_related_objects() /usr/lib/python3.7/site-packages/django/db/models/query.py in __iter__(self) 51 # Execute the query. This will also fill compiler.select, klass_info, 52 # and annotations. ---> 53 results = compiler.execute_sql(chunked_fetch=self.chunked_fetch) 54 select, klass_info, annotation_col_map = (compiler.select, compiler.klass_info, 55 compiler.annotation_col_map) /usr/lib/python3.7/site-packages/django/db/models/sql/compiler.py in execute_sql(self, result_type, chunked_fetch) 874 result_type = NO_RESULTS 875 try: --> 876 sql, params = self.as_sql() 877 if not sql: 878 raise EmptyResultSet /usr/lib/python3.7/site-packages/django/db/models/sql/compiler.py in as_sql(self, with_limits, with_col_aliases) 439 # (see docstring of get_from_clause() for details). 440 from_, f_params = self.get_from_clause() --> 441 where, w_params = self.compile(self.where) if self.where is not None else ("", []) 442 having, h_params = self.compile(self.having) if self.having is not None else ("", []) 443 result = ['SELECT'] /usr/lib/python3.7/site-packages/django/db/models/sql/compiler.py in compile(self, node, select_format) 371 sql, params = vendor_impl(self, self.connection) 372 else: --> 373 sql, params = node.as_sql(self, self.connection) 374 if select_format is FORCE or (select_format and not self.query.subquery): 375 return node.output_field.select_format(self, sql, params) /usr/lib/python3.7/site-packages/django/db/models/sql/where.py in as_sql(self, compiler, connection) 77 for child in self.children: 78 try: ---> 79 sql, params = compiler.compile(child) 80 except EmptyResultSet: 81 empty_needed -= 1 /usr/lib/python3.7/site-packages/django/db/models/sql/compiler.py in compile(self, node, select_format) 371 sql, params = vendor_impl(self, self.connection) 372 else: --> 373 sql, params = node.as_sql(self, self.connection) 374 if select_format is FORCE or (select_format and not self.query.subquery): 375 return node.output_field.select_format(self, sql, params) /usr/lib/python3.7/site-packages/django/contrib/postgres/lookups.py in as_sql(self, qn, connection) 9 lhs, lhs_params = self.process_lhs(qn, connection) 10 rhs, rhs_params = self.process_rhs(qn, connection) ---> 11 params = lhs_params + rhs_params 12 return '%s %s %s' % (lhs, self.operator, rhs), params 13 TypeError: can only concatenate tuple (not "list") to tuple
This appears to have been introduced in 1.11.25 when addressing this ticket: https://code.djangoproject.com/ticket/30769
While it is entirely possible that this is an incorrect use of contains
in this context to begin with, this is a breaking change for projects using 1.11.* with this syntax.
Attachments (1)
Change History (15)
comment:1 by , 5 years ago
Severity: | Normal → Release blocker |
---|---|
Summary: | Backwards-incompatible change to querying data within arrays in JSONFields using `contains` in 1.11.25 → Chaining __contains lookup with JSONField key transforms crashes. |
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 5 years ago
Cc: | added |
---|
comment:3 by , 5 years ago
Cc: | added |
---|
follow-up: 7 comment:5 by , 5 years ago
getting the same with chained __has_key
lookup (and i can assume any other chained lookups will crash)
comment:6 by , 5 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:7 by , 5 years ago
Replying to Roman Sichny:
getting the same with chained
__has_key
lookup (and i can assume any other chained lookups will crash)
just to confirm that my initial report (now closed as duplicate of this one) was about __has_key
comment:8 by , 5 years ago
Triage Stage: | Accepted → Ready for checkin |
---|
comment:9 by , 5 years ago
Cc: | added |
---|
Thanks for this report, yes it is a regression in the newest release.
Regression in 6c3dfba89215fc56fc27ef61829a6fff88be4abb.