Opened 5 months ago
Last modified 5 months ago
#36338 closed Bug
Grouping on JSONField subkey throws tuple index out of range error — at Initial Version
Reported by: | Marc DEBUREAUX | Owned by: | |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 5.2 |
Severity: | Normal | Keywords: | jsonfield |
Cc: | Marc DEBUREAUX | Triage Stage: | Unreviewed |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Have this simple model:
class Link(models.Model): item = models.ForeignKey("Item", on_delete=models.CASCADE) extra = models.JSONField(blank=True, null=True)
And have this simple query:
Link.objects.filter(item_id=1).values("extra__key").annotate(count=Count("id"))
This throws the following stacktrace error since 5.2 release:
--------------------------------------------------------------------------- IndexError Traceback (most recent call last) File ~/python3.12/site-packages/IPython/core/formatters.py:770, in PlainTextFormatter.__call__(self, obj) 763 stream = StringIO() 764 printer = pretty.RepresentationPrinter(stream, self.verbose, 765 self.max_width, self.newline, 766 max_seq_length=self.max_seq_length, 767 singleton_pprinters=self.singleton_printers, 768 type_pprinters=self.type_printers, 769 deferred_pprinters=self.deferred_printers) --> 770 printer.pretty(obj) 771 printer.flush() 772 return stream.getvalue() File ~/python3.12/site-packages/IPython/lib/pretty.py:411, in RepresentationPrinter.pretty(self, obj) 400 return meth(obj, self, cycle) 401 if ( 402 cls is not object 403 # check if cls defines __repr__ (...) 409 and callable(_safe_getattr(cls, "__repr__", None)) 410 ): --> 411 return _repr_pprint(obj, self, cycle) 413 return _default_pprint(obj, self, cycle) 414 finally: File ~/python3.12/site-packages/IPython/lib/pretty.py:786, in _repr_pprint(obj, p, cycle) 784 """A pprint that just redirects to the normal repr function.""" 785 # Find newlines and replace them with p.break_() --> 786 output = repr(obj) 787 lines = output.splitlines() 788 with p.group(): File ~/python3.12/site-packages/django/db/models/query.py:360, in QuerySet.__repr__(self) 359 def __repr__(self): --> 360 data = list(self[: REPR_OUTPUT_SIZE + 1]) 361 if len(data) > REPR_OUTPUT_SIZE: 362 data[-1] = "...(remaining elements truncated)..." File ~/python3.12/site-packages/django/db/models/query.py:384, in QuerySet.__iter__(self) 369 def __iter__(self): 370 """ 371 The queryset iterator protocol uses three nested iterators in the 372 default case: (...) 382 - Responsible for turning the rows into model objects. 383 """ --> 384 self._fetch_all() 385 return iter(self._result_cache) File ~/python3.12/site-packages/django/db/models/query.py:1935, in QuerySet._fetch_all(self) 1933 def _fetch_all(self): 1934 if self._result_cache is None: -> 1935 self._result_cache = list(self._iterable_class(self)) 1936 if self._prefetch_related_lookups and not self._prefetch_done: 1937 self._prefetch_related_objects() File ~/python3.12/site-packages/django/db/models/query.py:216, in ValuesIterable.__iter__(self) 210 names = [ 211 *query.extra_select, 212 *query.values_select, 213 *query.annotation_select, 214 ] 215 indexes = range(len(names)) --> 216 for row in compiler.results_iter( 217 chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size 218 ): 219 yield {names[i]: row[i] for i in indexes} File ~/python3.12/site-packages/django/db/models/sql/compiler.py:1571, in SQLCompiler.results_iter(self, results, tuple_expected, chunked_fetch, chunk_size) 1569 """Return an iterator over the results from executing this query.""" 1570 if results is None: -> 1571 results = self.execute_sql( 1572 MULTI, chunked_fetch=chunked_fetch, chunk_size=chunk_size 1573 ) 1574 fields = [s[0] for s in self.select[0 : self.col_count]] 1575 converters = self.get_converters(fields) File ~/python3.12/site-packages/django/db/models/sql/compiler.py:1609, in SQLCompiler.execute_sql(self, result_type, chunked_fetch, chunk_size) 1607 result_type = result_type or NO_RESULTS 1608 try: -> 1609 sql, params = self.as_sql() 1610 if not sql: 1611 raise EmptyResultSet File ~/python3.12/site-packages/django/db/models/sql/compiler.py:765, in SQLCompiler.as_sql(self, with_limits, with_col_aliases) 763 try: 764 combinator = self.query.combinator --> 765 extra_select, order_by, group_by = self.pre_sql_setup( 766 with_col_aliases=with_col_aliases or bool(combinator), 767 ) 768 for_update_part = None 769 # Is a LIMIT/OFFSET clause needed? File ~/python3.12/site-packages/django/db/models/sql/compiler.py:85, in SQLCompiler.pre_sql_setup(self, with_col_aliases) 79 def pre_sql_setup(self, with_col_aliases=False): 80 """ 81 Do any necessary class setup immediately prior to producing SQL. This 82 is for things that can't necessarily be done in __init__ because we 83 might not have all the pieces in place at that time. 84 """ ---> 85 self.setup_query(with_col_aliases=with_col_aliases) 86 order_by = self.get_order_by() 87 self.where, self.having, self.qualify = self.query.where.split_having_qualify( 88 must_group_by=self.query.group_by is not None 89 ) File ~/python3.12/site-packages/django/db/models/sql/compiler.py:74, in SQLCompiler.setup_query(self, with_col_aliases) 72 if all(self.query.alias_refcount[a] == 0 for a in self.query.alias_map): 73 self.query.get_initial_alias() ---> 74 self.select, self.klass_info, self.annotation_col_map = self.get_select( 75 with_col_aliases=with_col_aliases, 76 ) 77 self.col_count = len(self.select) File ~/python3.12/site-packages/django/db/models/sql/compiler.py:286, in SQLCompiler.get_select(self, with_col_aliases) 284 # Reference to a column. 285 elif isinstance(expression, int): --> 286 expression = cols[expression] 287 # ColPairs cannot be aliased. 288 if isinstance(expression, ColPairs):
Note:
See TracTickets
for help on using tickets.