Skip to content

Commit

Permalink
Fix after filter when ordering on annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
daanvdk committed May 23, 2024
1 parent 3388534 commit 5fae211
Showing 1 changed file with 29 additions and 9 deletions.
38 changes: 29 additions & 9 deletions binder/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -1543,20 +1543,31 @@ def _apply_q_with_possible_annotations(self, queryset, q, annotations):
return queryset.filter(q)


def _after_expr(self, request, after_id):
def _after_expr(self, request, after_id, include_annotations):
"""
This method given a request and an id returns a boolean expression that
indicates if a record would show up after the provided id for the
ordering specified by this request.
"""
# First we get the object we need to use as our base for our filter
queryset = self.get_queryset(request)
annotations = {
name: value['expr']
for name, value in self.annotations(request, include_annotations).items()
}

# We do an order by on a copy of annotations so that we see which keys
# it pops
annotations_copy = annotations.copy()
ordering = self._order_by_base(queryset, request, annotations_copy).query.order_by
required_annotations = set(annotations) - set(annotations_copy)

queryset = queryset.annotate(**{name: annotations[name] for name in required_annotations})
try:
obj = self.get_queryset(request).get(pk=int(after_id))
obj = queryset.get(pk=int(after_id))
except (ValueError, self.model.DoesNotExist):
raise BinderRequestError(f'invalid value for after_id: {after_id!r}')

# Now we will build up a comparison expr based on the order by
ordering = self.order_by(self.model.objects.all(), request).query.order_by
left_exprs = []
right_exprs = []

Expand Down Expand Up @@ -1587,9 +1598,11 @@ def _after_expr(self, request, after_id):

# Now we turn this into one big comparison
if len(ordering) == 1:
return GreaterThan(left_exprs[0], right_exprs[0])
expr = GreaterThan(left_exprs[0], right_exprs[0])
else:
return GreaterThan(Tuple(*left_exprs), Tuple(*right_exprs))
expr = GreaterThan(Tuple(*left_exprs), Tuple(*right_exprs))

return expr, required_annotations


def _get_filtered_queryset_base(self, request, pk=None, include_annotations=None):
Expand All @@ -1611,7 +1624,7 @@ def _get_filtered_queryset_base(self, request, pk=None, include_annotations=None

annotations = {
name: value['expr']
for name, value in get_annotations(queryset.model, request, include_annotations.get('')).items()
for name, value in self.annotations(request, include_annotations).items()
}

#### filters
Expand All @@ -1635,8 +1648,15 @@ def _get_filtered_queryset_base(self, request, pk=None, include_annotations=None
except KeyError:
pass
else:
expr = self._after_expr(request, after)
queryset = queryset.filter(expr)
after_expr, required_annotations = self._after_expr(request, after, include_annotations)
for name in required_annotations:
try:
expr = annotations.pop(name)
except KeyError:
pass
else:
queryset = queryset.annotate(**{name: expr})
queryset = queryset.filter(after_expr)

return queryset, annotations

Expand Down

0 comments on commit 5fae211

Please sign in to comment.