使用DataLoader模式消灭N+1查询:在Django REST中批量加载关联数据
借鉴GraphQL DataLoader概念,为DRF序列化器或自定义视图实现按需批量加载,减少数据库查询次数。 · 难度:入门 · +10XP
异步批量加载器
REST API中嵌套序列化器常导致N+1。本教程实现一个DataLoader类,它在一次请求生命周期内收集所有需要的关联ID,然后批量查询并返回字典映射。使用threading.local存储当前请求的loader实例,并支持缓存和过期。你可以在序列化器的to_representation中调用loader.load(id),框架自动合并查询。相比prefetch_related,该方法更灵活,支持跨模型聚合。
from collections import defaultdict
import threading
class DataLoader:
def __init__(self, batch_load_fn):
self._batch_load_fn = batch_load_fn
self._keys = []
self._cache = {}
def load(self, key):
if key not in self._cache:
self._keys.append(key)
# 在视图结束时统一执行
return self._cache
def dispatch(self):
results = self._batch_load_fn(self._keys)
for k, v in zip(self._keys, results):
self._cache[k] = v