在 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)
请注意,与之前针对主查询集中的每个对象的一个额外查询相比,这将导致一个额外的查询来预取所有相关对象(因此总共有两个查询,无论您获取多少行)。
我有一个模型 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)
请注意,与之前针对主查询集中的每个对象的一个额外查询相比,这将导致一个额外的查询来预取所有相关对象(因此总共有两个查询,无论您获取多少行)。