Django QuerySet反向引用过滤:筛选关联Choice的已发布Question
高效筛选符合条件的Question QuerySet
针对你的需求,直接用Django ORM的查询语法就能一次性完成过滤,避免遍历带来的性能问题,以下是几种可行的方案:
方案1:利用外键非空过滤+去重
如果你的Choice模型有指向Question的外键(假设外键字段名为question),可以直接通过choice__isnull=False过滤出有关联选项的问题,同时结合发布时间条件:
from django.utils import timezone from .models import Question valid_questions = Question.objects.filter( pub_date__lt=timezone.now(), choice__isnull=False ).distinct()
- 加
distinct()是因为一个问题如果对应多个选项,查询结果会重复,去重后得到唯一的问题集合 - 整个查询只会触发一次数据库请求,性能远高于遍历查询
方案2:通过注解计数过滤
用annotate给每个问题添加关联选项的计数,再过滤计数大于0的结果:
from django.db.models import Count from django.utils import timezone from .models import Question valid_questions = Question.objects.filter( pub_date__lt=timezone.now() ).annotate( choice_count=Count('choice') ).filter( choice_count__gt=0 )
- 这种方式不需要额外去重,因为
annotate会按Question分组统计选项数量 - 同样是单次数据库查询,结果更直观(可以直接拿到每个问题的选项数)
方案3:子查询判断存在性
用Exists子查询明确判断当前问题是否存在关联的选项,逻辑更清晰:
from django.db.models import Exists, OuterRef from django.utils import timezone from .models import Question, Choice valid_questions = Question.objects.filter( pub_date__lt=timezone.now(), Exists(Choice.objects.filter(question=OuterRef('pk'))) )
- 这种写法和方案1性能接近,但可读性更强,适合复杂关联场景
关于你之前的报错
你提到用pk报错,大概率是写法有误,比如错误使用了choice__pk__exists这类语法,以上三种方案都不需要手动处理pk,ORM会自动处理关联条件。
内容的提问来源于stack exchange,提问作者wsys
相关产品推荐
相关产品推荐

