Warm tip: This article is reproduced from serverfault.com, please click

python-过滤Django时保持注释等级

(python - Keeping annotated rank when filtering Django)

发布于 2020-11-28 06:20:31

我有一个已过滤的Queryset,其中已根据特定顺序注释了每个对象的等级。

然后,当我执行其他过滤器(如按等级更改顺序)时,保持不变。问题是在执行新的.filter()时出现

我在页面上有一个搜索功能,该功能可以在对象标题之后过滤结果。但是,当我这样做时,带注释的等级值会根据新查询中有多少个结果而不是保持其原始值而变化。

为了显示:

这是我的原始查询:

choices_filter = Choice.objects.filter(tournament=pk).annotate \
    (rank=RawSQL("RANK() OVER(ORDER BY winrate DESC, pickrate DESC, times_played)", []))

这将返回一个查询集,如下所示:

Rank        Title         Winrate      
1...........Apple...........55%
2...........Pear............47%
3...........Banana..........44%
4...........Orange..........35%
5...........Watermelon......31%

如果执行.order_by('title'),则会得到以下预期结果:

Rank        Title         Winrate      
1...........Apple...........55%
3...........Banana..........44%
4...........Orange..........35%
2...........Pear............47%
5...........Watermelon......31%

但是,如果我改为执行.filter(title__icontains ='an'),则会得到以下信息:

Rank        Title         Winrate      
1...........Banana..........44%
2...........Orange..........35%

而不是所需的:

Rank        Title         Winrate      
3...........Banana..........44%
4...........Orange..........35%

我仍然对Django和python(以及数据库)还没有足够的经验来独自浏览。我花了好一会儿才弄清楚如何注释等级并使其与分页一起使用。

如果相关,这是我的完整View代码(我正在使用Django Rest Framework和APIviews):

class GameDetailFilterView(APIView, PaginationHandlerMixin):
    permission_classes = (AllowAny, )
    pagination_class = FullPagination
    serializer_class = ChoiceSerializer

    def get(self, request, pk, *args, **kwargs):
        choices_filter = Choice.objects.filter(tournament=pk).annotate \
            (rank=RawSQL("RANK() OVER(ORDER BY winrate DESC, pickrate DESC, times_played)", []))
        filter_condition = request.session['filter_condition']
        if filter_condition is not None:
            choices = choices_filter.filter(title__icontains=filter_condition)
        else:
            choices = choices_filter.order_by('rank')

        page = self.paginate_queryset(choices)

        if page is not None:
            serializer = self.get_paginated_response(self.serializer_class(page,
                                                                           many=True).data)
        else:
            serializer = self.serializer_class(choices, many=True)
        return Response(serializer.data, status=status.HTTP_200_OK)
Questioner
Josie
Viewed
0
ahmadgh74 2020-11-28 17:42:34

你可以使用django-cte

from django_cte import CTEManager, With

# models.py
class Choice(Model):
    objects = CTEManager()
    # ... other fields like tournament

# query 
cte = With(
Choice.objects.filter(tournament=pk).annotate \
(rank=RawSQL("RANK() OVER(ORDER BY winrate DESC, pickrate DESC,times_played)", [])))
qs = cte.queryset().with_cte(cte).filter(title__icontains='an')

并点击此链接