You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

DRF自定义QuerySet未按预期重新评估的问题咨询

问题结论

这是DRF的预期工作行为,问题根源不在DRF的实现逻辑,而在自定义QuerySet的执行特性和Django类属性的加载时机。

原因说明
  • Django类视图的类属性会在模块首次加载阶段就完成计算,并非每次请求时动态计算。
  • 你自定义的world_rankings方法中调用了.first(),这是会立即触发SQL执行的操作:当你把queryset = Ranking.objects.world_ranking()作为类属性赋值时,world_ranking方法会在类加载阶段直接运行,此时你的测试数据还未通过setUpTestData插入,所以拿到的update为空,返回的是固定的空QuerySet。
  • DRF默认get_queryset方法中调用.all()的作用,是让未执行的惰性QuerySet重新拉取数据,但是你赋值给queryset属性的已经是执行后返回的空QuerySet,后续无论怎么调用.all()都只会基于已经确定的过滤条件返回空结果。
  • 你换成普通filter操作能正常运行的原因是:普通filter不会触发立即执行,类加载阶段只是生成了带过滤规则的惰性QuerySet,直到请求处理时才会真正执行SQL,自然能拿到后来插入的测试数据。
优化方案

除了自定义get_queryset(这也是DRF官方推荐的动态QuerySet标准写法)之外,你也可以修改自定义QuerySet方法,去掉立即执行的操作,让整个查询变成完全惰性的,就可以直接赋值给类属性使用:

class RankingQuerySet(models.QuerySet):
    def world_rankings(self, rank_type="World"):
        # 用子查询替代first(),避免立即触发SQL执行
        latest_update_subquery = RankingUpdate.objects.issued().filter(
            rank_type=rank_type, date__lte=TODAY
        ).order_by("-asat", "-date").values("id")[:1]
        return self.filter(
            update_id__in=latest_update_subquery,
            player_id__gt=0,
            points__gt=0
        )

修改后原来的视图写法不需要变动,每次请求都会自动重新执行查询拿到最新数据。

内容的提问来源于stack exchange,提问作者PhoebeB

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 04:54:04