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

Django REST Framework嵌套序列化器中子序列化器如何使用预取查询集

问题原因与解决方案

报错根因

  • 你当前的写法user.emailaddress_set.filter(verified=1).count()没有命中prefetch_related预取的缓存数据,会触发新的SQL查询,部分数据库(如PostgreSQL)不支持直接对布尔字段执行此类聚合查询,所以抛出function max(boolean) does not exist错误。
  • 只要调用filter、count这类QuerySet方法,就会绕开已经预取到内存的数据集,直接请求数据库,完全浪费了预取的性能优化效果。

正确实现(命中预取缓存)

直接操作已经加载到内存的关联数据集,不触发新的数据库查询,修改UserDetailSerializer中的get_is_verified方法即可:

def get_is_verified(self, user):
    # 直接遍历预取到内存的所有邮箱对象,不触发新查询
    return any(email.verified for email in user.emailaddress_set.all())

进阶优化(减少预取数据量)

如果只需要判断是否存在已验证邮箱,可以在预取阶段就过滤数据,进一步降低内存开销:

  1. 修改视图层的查询集逻辑,使用Prefetch自定义预取规则:
from django.db.models import Prefetch

class PlaylistListView(generics.ListAPIView):
    serializer_class = PlaylistSerializer

    def get_queryset(self):
        return (
            Playlist.objects.all()
            # user是单对一外键,用select_related比prefetch_related性能更好
            .select_related("user")
            .prefetch_related(
                Prefetch(
                    "user__emailaddress_set",
                    # 预取阶段只过滤已验证的邮箱
                    queryset=EmailAddress.objects.filter(verified=True),
                    # 自定义属性名存储预取结果
                    to_attr="verified_emails"
                )
            )
        )
  1. 序列化层直接判断自定义预取属性的长度即可:
def get_is_verified(self, user):
    return len(user.verified_emails) > 0

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 16:57:04