Opened 7 months ago
Last modified 7 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.