in src/olympia/search/filters.py [0:0]
def filter_queryset(self, request, qs, view):
search_query_param = request.GET.get('q')
split_sort_params = self.get_sort_params(request)
if split_sort_params:
# Random sort is a bit special.
# First, it can't be combined with other sorts.
if 'random' in split_sort_params and len(split_sort_params) > 1:
raise serializers.ValidationError(
'The "random" "sort" parameter can not be combined.'
)
# Second, for perf reasons it's only available when the 'featured'
# or 'promoted' param is present (to limit the number of
# documents we'll have to apply the random score to) and a search
# query is absent (to prevent clashing with the score functions
# coming from a search query).
if split_sort_params == ['random']:
is_random_sort_available = (
AddonFeaturedQueryParam.query_param in request.GET
or AddonPromotedQueryParam.query_param in request.GET
) and not search_query_param
if is_random_sort_available:
# Third, we want randomness to change only once every hour,
# so we use a seed that depends on the date + hour.
now = datetime.now()
qs = qs.query(
'function_score',
functions=[
query.SF(
'random_score',
seed=now.toordinal() * 24 + now.hour,
field='id',
)
],
)
else:
raise serializers.ValidationError(
'The "sort" parameter "random" can only be specified '
'when the "featured" or "promoted" parameter is '
'also present, and the "q" parameter absent.'
)
# Sorting by relevance only makes sense with a query string
if not search_query_param and 'relevance' in split_sort_params:
split_sort_params = [
param for param in split_sort_params if not 'relevance'
]
# Having just recommended sort doesn't make any sense, so ignore it
if split_sort_params == ['recommended']:
split_sort_params = None
# relevance already takes into account recommended so ignore it too
elif (
'recommended' in split_sort_params and 'relevance' in split_sort_params
):
split_sort_params = [
param for param in split_sort_params if not 'recommended'
]
if not split_sort_params:
# The default sort depends on the presence of a query: we sort by
# relevance if we have a query, otherwise by recommended,downloads.
split_sort_params = (
['relevance'] if search_query_param else ['recommended', 'users']
)
try:
order_by = [self.SORTING_PARAMS[name] for name in split_sort_params]
except KeyError as exc:
raise serializers.ValidationError('Invalid "sort" parameter.') from exc
return qs.sort(*order_by)