QuerySet 的三种优雅写法

自定义 Manager、链式过滤、annotate 聚合——把查询逻辑从视图里抽出来。

A
QuerySet 的三种优雅写法

1. 把常用条件收进 QuerySet

视图里反复写 filter(status='published', publish_at__lte=now) 很快会失控。更好的做法是定义语义化的方法:

class PostQuerySet(models.QuerySet):
    def published(self):
        return self.filter(
            status=Post.Status.PUBLISHED,
            publish_at__lte=timezone.now(),
        )

    def ordered(self):
        return self.order_by('-pinned', '-publish_at')

调用时就变成 Post.objects.published().ordered(),意图一眼可见。

2. 链式而不是嵌套

QuerySet 是惰性的,链式调用不会产生额外查询:

qs = Post.objects.published()
if category:
    qs = qs.filter(category=category)
if query:
    qs = qs.filter(Q(title__icontains=query) | Q(content__icontains=query))

比一堆 if/else 拼 SQL 字符串可读得多。

3. 用 annotate 把统计交给数据库

需要“每个分类下有几篇文章”时,不要在模板里循环查询:

Category.objects.annotate(
    post_count=Count('posts', filter=Q(posts__status='published'))
)

一次查询拿到全部计数,避免 N+1。

小结

写法 收益
自定义 QuerySet 语义清晰、可复用
链式过滤 组合灵活、惰性执行
annotate 消除 N+1、逻辑下沉
← 返回文章列表

评论

1 条
R
reader 2026-10-31 21:08

annotate 那段很实用,之前确实一直在模板里循环查询。

KEEP READING

相关文章

全部文章 →