Sorting a public view by a multiselect and another field type can cause crashes
Describe the problem
Both the public grid view API endpoint and the list rows endpoint support the order_by=
get parameter. This param is then used by the order_by_fields_string
method. This method has a logical bug where it only ever applies a single Annotation from an AnnotatedOrder even if there could be N different annotations.
Traceback (most recent call last):
File "/baserow/venv/lib/python3.7/site-packages/asgiref/sync.py", line 482, in thread_handler
raise exc_info[1]
File "/baserow/venv/lib/python3.7/site-packages/django/core/handlers/exception.py", line 38, in inner
response = await get_response(request)
File "/baserow/venv/lib/python3.7/site-packages/django/core/handlers/base.py", line 233, in _get_response_async
response = await wrapped_callback(request, *callback_args, **callback_kwargs)
File "/baserow/venv/lib/python3.7/site-packages/asgiref/sync.py", line 444, in __call__
ret = await asyncio.wait_for(future, timeout=None)
File "/usr/lib/python3.7/asyncio/tasks.py", line 388, in wait_for
return await fut
File "/baserow/venv/lib/python3.7/site-packages/asgiref/current_thread_executor.py", line 22, in run
result = self.fn(*self.args, **self.kwargs)
File "/baserow/venv/lib/python3.7/site-packages/asgiref/sync.py", line 486, in thread_handler
return func(*args, **kwargs)
File "/baserow/venv/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/baserow/venv/lib/python3.7/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/baserow/venv/lib/python3.7/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/baserow/venv/lib/python3.7/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/baserow/venv/lib/python3.7/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/baserow/venv/lib/python3.7/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/baserow/backend/src/baserow/api/decorators.py", line 83, in func_wrapper
return func(*args, **kwargs)
File "/baserow/backend/src/baserow/api/decorators.py", line 145, in func_wrapper
return func(*args, **kwargs)
File "/baserow/backend/src/baserow/contrib/database/api/rows/views.py", line 314, in get
page = paginator.paginate_queryset(queryset, request, self)
File "/baserow/backend/src/baserow/api/pagination.py", line 37, in paginate_queryset
return super().paginate_queryset(*args, **kwargs)
File "/baserow/venv/lib/python3.7/site-packages/rest_framework/pagination.py", line 216, in paginate_queryset
return list(self.page)
File "/baserow/venv/lib/python3.7/site-packages/django/core/paginator.py", line 177, in __len__
return len(self.object_list)
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/query.py", line 262, in __len__
self._fetch_all()
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/query.py", line 1324, in _fetch_all
self._result_cache = list(self._iterable_class(self))
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/query.py", line 51, in __iter__
results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size)
File "/baserow/venv/lib/python3.7/site-packages/silk/sql.py", line 66, in execute_sql
q, params = self.as_sql()
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 513, in as_sql
extra_select, order_by, group_by = self.pre_sql_setup()
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 56, in pre_sql_setup
order_by = self.get_order_by()
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/sql/compiler.py", line 372, in get_order_by
resolved = expr.resolve_expression(self.query, allow_joins=True, reuse=None)
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/expressions.py", line 250, in resolve_expression
for expr in c.get_source_expressions()
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/expressions.py", line 250, in <listcomp>
for expr in c.get_source_expressions()
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/expressions.py", line 578, in resolve_expression
return query.resolve_ref(self.name, allow_joins, reuse, summarize)
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/sql/query.py", line 1779, in resolve_ref
join_info = self.setup_joins(field_list, self.get_meta(), self.get_initial_alias(), can_reuse=reuse)
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/sql/query.py", line 1649, in setup_joins
names[:pivot], opts, allow_many, fail_on_missing=True,
File "/baserow/venv/lib/python3.7/site-packages/django/db/models/sql/query.py", line 1563, in names_to_path
"Choices are: %s" % (name, ", ".join(available)))
django.core.exceptions.FieldError: Cannot resolve keyword 'field_2016_agg_sort' into field. Choices are: created_on, field_1985, field_1986, field_1987, field_1988, field_1992, field_1993, field_1994, field_1995, field_1996, field_1997, field_1998, field_1999, field_2000, field_2001, field_2002, field_2003, field_2004, field_2005, field_2006, field_2007, field_2008, field_2009, field_2010, field_2011, field_2012, field_2013, field_2014, field_2015, field_2016, field_2017, field_2018, field_2019, field_2020, field_2021, field_2022, field_2023, field_2024, field_2025, field_2030, field_2032, field_2033, id, order, trashed, updated_on
Fix:
Index: backend/src/baserow/contrib/database/table/models.py
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/backend/src/baserow/contrib/database/table/models.py b/backend/src/baserow/contrib/database/table/models.py
--- a/backend/src/baserow/contrib/database/table/models.py (revision 12cc2d1cc37f5af0d5dd6d8605b032b3aaa68ab3)
+++ b/backend/src/baserow/contrib/database/table/models.py (date 1657883475256)
@@ -171,6 +171,7 @@
else:
field_object_dict = self.model._field_objects
+ annotations = {}
for index, order in enumerate(order_by):
if user_field_names:
field_name_or_id = self._get_field_name(order)
@@ -199,10 +200,9 @@
)
field_order = field_type.get_order(field, field_name, order_direction)
- annotation = None
if isinstance(field_order, AnnotatedOrder):
- annotation = field_order.annotation
+ annotations = {**annotations, **field_order.annotation}
field_order = field_order.order
if field_order:
@@ -220,8 +220,8 @@
order_by.append("order")
order_by.append("id")
- if annotation is not None:
- return self.annotate(**annotation).order_by(*order_by)
+ if annotations is not None:
+ return self.annotate(**annotations).order_by(*order_by)
else:
return self.order_by(*order_by)
Edited by Nigel Gott