Django ORM使用嵌套Prefetch时如何避免重复编写过滤条件
解决方案
完全可以避免重复编写过滤条件,有两种常用的实现方式:
方式1:抽取公共过滤条件变量
直接把重复的Q对象提取为公共变量,两处复用即可,修改后的代码如下:
# 先定义公共的状态过滤条件 active_status_filter = Q(status=TestInstance.RUNNING) | Q(status=TestInstance.CREATING) queryset = User.objects.filter( testinstance__status__in=[TestInstance.RUNNING, TestInstance.CREATING] ).order_by('first_name').prefetch_related(Prefetch( 'testinstance_set', queryset=TestInstance.objects.filter(active_status_filter).order_by('-started_at') )).distinct()
补充:你原来的外层filter还可以简化成testinstance__status__in的写法,不需要写Q或逻辑,可读性更高
方式2:给模型自定义查询集方法(更适合复用场景多的情况)
如果这个状态过滤逻辑在业务里多处用到,可以给TestInstance加自定义管理器方法,后续所有查询都可以直接调用,不需要重复写条件:
class TestInstanceQuerySet(models.QuerySet): def active(self): return self.filter(Q(status=TestInstance.RUNNING) | Q(status=TestInstance.CREATING)) class TestInstance(models.Model): author = models.ForeignKey(User, on_delete=models.CASCADE) # 其他字段定义... objects = TestInstanceQuerySet.as_manager()
之后你的业务代码可以简化成:
queryset = User.objects.filter( testinstance__status__in=[TestInstance.RUNNING, TestInstance.CREATING] ).order_by('first_name').prefetch_related(Prefetch( 'testinstance_set', queryset=TestInstance.objects.active().order_by('-started_at') )).distinct()
如果后续需要调整active对应的状态范围,只要改模型里的active方法即可,所有调用的地方都会同步生效,维护成本更低。
内容的提问来源于stack exchange,提问作者guest381
相关产品推荐
相关产品推荐

