在 Django ORM 中过滤关系字段

Filter on relation field in Django ORM

我有一个模型 Media 与模型 UserMedia(用户评分)有关系。还有一个与问题相关的名为 UserMatchScore(匹配用户分数)的模型。

在一个视图中,我正在查询媒体 table,在这个视图中,有一个选项可以只获取我的比赛已经评级但我没有评级的媒体。此外,根据我和我的比赛的子集返回平均评分,而不是所有对媒体评分的用户。我用注释来做到这一点。

我所做的是过滤媒体 table 中我未评价但我的比赛已评价的元素,这很简单,但只完成了一半的工作。返回所有我没有评分的媒体,但我的比赛已经评分,但是关系字段 UserMedia 仍然包含所有评分,这个没有被过滤,所以没有办法计算我的比赛子集的平均评分. 这是我正在描述的查询:

queryset = models.Media.objects
queryset = queryset.filter(
               Q(usermedia__user__id__in=my_matches) & ~Q(usermedia__user=user)
            )

获得预期结果的唯一方法是遍历查询集并过滤 UserMedia 关系的每个元素,但这太慢了,因此必须通过数据库查询来完成。

for el in queryset:                    
    el.usermedia_set.filter(~Q(user=user)).filter(user=my_matches)

有谁知道如何使用 Django ORM 执行此操作?

使用Prefetch,您可以使用预先过滤的查询集获取关系(对于多对多和反向外键关系)的相关对象:

queryset = queryset.filter(
               Q(usermedia__user__id__in=my_matches) & ~Q(usermedia__user=user)
            )

prefetch = UserMedia.objects.filter(user_id__in=my_matches).exclude(user=user)
queryset = queryset.prefetch_related(
    Prefetch('usermedia_set', prefetch, to_attr='filtered_usermedia')
)

for el in queryset:
    for usermedia in el.filtered_usermedia:
        # iterate over the filtered usermedia
        # without any additional queries
        calculate_something(usermedia)                    

请注意,与之前针对主查询集中的每个对象的一个​​额外查询相比,这将导致一个额外的查询来预取所有相关对象(因此总共有两个查询,无论您获取多少行)。