有没有办法告诉prefetch_related
只获取一组有限的相关对象?让我们说我正在获取一个用户列表,我知道我想获取他们最近的评论。我没有在循环中为每个用户提取注释,而是在获取用户时使用prefetch_related预取它们。我的理解是,这将获取原始查询结果中出现的任何用户所做的所有评论,但我只想为每个用户显示最新的5条。
如果评论列表真的很大,这对性能有何影响?有没有办法在单个(或2个)查询中为每个用户仅获取5条评论?它不必与用于获取用户的原始查询相同,但这样会很好。
我基本上想转此
users = User.objects.all()
for user in users:
user.comments.all()[:10]
这样的事情
User.objects.all().prefetch_related('comments', limit=10)
因此,如果用户有100或10000条评论,则它们不会全部加载到内存中。你会如何在原始SQL中做这样的事情?
答案 0 :(得分:9)
我认为django新版本现在有一个解决方法,因为我们有OuterRef和Subquery。
from django.db.models import OuterRef, Subquery, Prefetch
subqry = Subquery(Comment.objects \
.filter(user_id=OuterRef('user_id')) \
.values_list('id', flat=True)[:5])
User.objects.prefetch_related(
Prefetch('comments', queryset=Comment.objects.filter(id__in=subqry)))
答案 1 :(得分:5)
限制预取相关对象数量的唯一方法似乎是使用Prefetch()和对fileds进行过滤。使用切片
User.objects.all().prefetch_related(
Prefetch('msg_sent', queryset=UserMsg.objects.order_by('-created')[:10]))
返回错误
AssertionError: Cannot filter a query once a slice has been taken.
限制相关对象数量的唯一方法似乎是对值使用过滤器,例如
from datetime import datetime, timedelta
timelimit = datetime.now() - timedelta(days=365)
User.objects.all().prefetch_related(
Prefetch('msg_sent', queryset=UserMsg.objects.filter(created__gte=timelimit)))
虽然这不会返回固定数字,但在某些情况下可能会有用,并且会减少预取对象的数量。
答案 2 :(得分:2)
多数民众赞成在我真正的工作django(2.1)(基于haseebahmad答案)。
为了使prefetch_related接受自定义查询集:Prefetch
所以:
从django.db.models导入OuterRef,Subquery,Prefetch
User.objects.all().prefetch_related(Prefetch('comment_set',
queryset=Comment.objects.filter(id__in=
Subquery(Comment.objects.filter(user_id=OuterRef('user_id')).
values_list('id', flat=True)[:1]))))