Django使用Case&When(条件表达式)注释排除

时间:2019-05-25 17:16:50

标签: django

我正在使用Django 2.2

在制作查询集时,我希望根据一些条件来计算相关模型

    queryset = self.model.objects.filter(user=self.request.user).annotate(
        count_videos=Count('video'),
        count_completed=Count(
            Case(
                When(video__status__in=Video.STATUS_LIST_COMPLETED)
            )
        ),
        count_failed=Count(
            Case(
                When(video__status__in=Video.STATUS_LIST_FAILED)
            )
        ),
        count_pending=Count(
            Case(
                When(
                    video__status__not_in=Video.STATUS_LIST_PENDING_EXCLUDE
                )
            )
        )
    )

这里有3个计数有效,但是在最后一个计数count_pending中,我必须计数为exlude()。即,对不包括传递的列表在内的记录数进行计数。

如何将exclude与上述声明一起使用?

2 个答案:

答案 0 :(得分:2)

我们可以否定传递给filter= parameter [Django-doc]的值:

from django.db.models import Count, Q

queryset = self.model.objects.filter(user=self.request.user).annotate(
    count_videos=Count('video'),
    count_completed=Count(
        'video',
        filter=Q(video__status__in=STATUS_LIST_COMPLETED)
    ),
    count_failed=Count(
        'video',
        filter=Q(video__status__in=Video.STATUS_LIST_FAILED)
    ),
    count_pending=Count(
        'video',
        filter=~Q(video__status__in=Video.STATUS_LIST_PENDING_EXCLUDE)
    )
)

这将导致如下查询:

SELECT model.*,
    COUNT(
        CASE WHEN NOT video.status IN STATUS_LIST_PENDING_EXCLUDE
                  AND video.status IS NOT NULL
        THEN video.id
        ELSE NULL END
    ) AS count_pending
FROM model
LEFT OUTER JOIN video ON model.id = video.model_id
GROUP BY model.id

答案 1 :(得分:0)

很抱歉回复了一个非常老的问题,但这个问题在搜索此主题时的命中率很高。我需要一个非常相似的东西并想要一个计数,但有一些奇怪的条件我无法用 ~Q 解决并登陆一个注释,如下所示。在这里发布仅适用于碰巧需要类似东西的人。

我需要对已完成和正在进行的评论进行计数,但如果 review.status 未受影响,则不会在“进行中”或“已完成”箱中计数。我使用 Case 并将“非”条件(未完成)的默认值设置为 1,然后将 Case 包装在 Sum 中,如图所示。大约有 9 种不同的状态表示“进行中”,我不想一一列举。

.values(___bunch_of_group_by_fields_here___)\
.annotate(
    completed=Sum(Case(
        When(status__in=[Review.REVIEW_COMPLETE,
                         ], then=Value(1)),
        default=Value(0),
        output_field=IntegerField(),
    )),
    # essentially: ( not (review complete or untouched) )
    # gets all the status between untouched (default first step) and 
    # complete (final status in the workflow for a review) without having 
    # to specify all the in between statuses
    inprogress=Sum(Case(
        When(status__in=[Review.REVIEW_COMPLETE,
                         Review.UNTOUCHED
                         ], then=Value(0)),
        default=Value(1),
        output_field=IntegerField(),
    ))