Django查询问题:如何基于根查询的值实现Prefetch筛选?
问题分析
你遇到的核心问题是:Prefetch的queryset是独立构建的,无法直接引用外层Profile对象的series_following_id——因为在执行Prefetch查询时,还没拿到具体的Profile实例,所以直接写series_id=series_following_id会报错。下面给你两种可行的解决方案,其中第二种能满足你“一次性查询”的需求。
方案1:分步查询(简单易理解)
如果对查询次数要求不高,可以先获取Profile对象,再基于它的series_following过滤关联的书籍:
# 先获取当前用户的Profile,只取需要的字段 profile = Profile.objects.only('id', 'series_following').get(user=request.user_id) # 过滤出属于关注系列的在读书籍 profile.books = profile.books_reading.filter(series=profile.series_following).only('id')
这种方式逻辑清晰,适合快速实现,但会产生两次数据库查询。
方案2:用FilteredRelation实现一次性查询(推荐)
Django 2.0及以上版本支持FilteredRelation,它允许你在查询时定义一个过滤后的关联关系,通过F()表达式引用外层模型的字段,完美匹配你的需求:
from django.db.models import FilteredRelation, Q, F profile = Profile.objects.only('id', 'series_following').annotate( # 定义一个过滤后的关联:只保留属于当前关注系列的books_reading filtered_books=FilteredRelation( 'books_reading', condition=Q(books_reading__series=F('series_following')) ) ).prefetch_related( # 预取这个过滤后的关联,只获取Book的id字段,并存到profile.books属性 Prefetch('filtered_books', queryset=Book.objects.only('id'), to_attr='books') ).get(user=request.user_id)
这里的关键是F('series_following')——它会动态引用当前Profile对象的series_following字段值,让过滤条件和外层查询关联起来,最终只需要一次数据库查询就能拿到所有需要的数据。
兼容旧版本Django的方案(用子查询)
如果你使用的是Django 2.0以下版本,可以用Subquery和Exists来实现:
from django.db.models import Subquery, OuterRef, Exists # 构建子查询:找到属于当前Profile关注系列的所有书籍 series_books = Book.objects.filter(series=OuterRef('series_following')) profile = Profile.objects.only('id', 'series_following').prefetch_related( Prefetch( 'books_reading', # 过滤出同时在books_reading和series_books里的书籍 queryset=Book.objects.only('id').filter(Exists(series_books.filter(id=OuterRef('id')))), to_attr='books' ) ).get(user=request.user_id)
内容的提问来源于stack exchange,提问作者Clas Yusa
相关产品推荐
相关产品推荐

