和 Spring Boot 对比:Spring Data JPA 用 @Query 注解或方法名约定(findByStatusAndCreatedAtAfter),Django 用链式调用 filter().order_by()。两者最终都生成 SQL,但 Django 的查询 API 更灵活、组合性更强。
先建立图像
Python 链式调用 生成的 SQL
──────────────────────────────────── ─────────────────────────────
Article.objects SELECT * FROM article
.filter(status="published") WHERE status = 'published'
.exclude(author__username="admin") AND author.username != 'admin'
.order_by("-created_at") ORDER BY created_at DESC
[:10] LIMIT 10
跟着做
步骤 1:双下划线 lookup 速查
Django 用双下划线 __ 表示字段查询操作符:
from blog.models import Article
from django.contrib.auth.models import User
# 等于(默认)
Article.objects.filter(status="published")
# 不等于
Article.objects.exclude(status="draft")
# 大于/小于
Article.objects.filter(views__gt=100) # views > 100
Article.objects.filter(views__gte=100) # views >= 100
Article.objects.filter(views__lt=1000) # views < 1000
# 范围
Article.objects.filter(views__range=(100, 1000)) # BETWEEN 100 AND 1000
# 模糊匹配
Article.objects.filter(title__contains="Django") # LIKE '%Django%'(区分大小写)
Article.objects.filter(title__icontains="django") # LIKE '%django%'(不区分)
Article.objects.filter(title__startswith="Python")
Article.objects.filter(title__endswith="教程")
# IN 查询
Article.objects.filter(id__in=[1, 2, 3, 4])
# 日期查询
Article.objects.filter(created_at__year=2024)
Article.objects.filter(created_at__month=8)
Article.objects.filter(created_at__date="2024-08-01")
# 关联查询(跨表用双下划线)
Article.objects.filter(author__username="alice") # JOIN auth_user
Article.objects.filter(category__name="Python") # JOIN category
Article.objects.filter(tags__name__icontains="django") # JOIN 中间表 + tag
# NULL 判断
Article.objects.filter(category__isnull=True)
# 正则匹配
Article.objects.filter(slug__regex=r"^django-\d+")
步骤 2:链式调用与惰性求值
QuerySet 是「惰性」的,直到你真正迭代/切片/取长度时才执行 SQL:
qs = Article.objects.filter(status="published") # 还没执行 SQL
qs = qs.order_by("-created_at") # 还没执行
qs = qs[:10] # 还没执行
for a in qs: # 此刻才执行 SELECT
print(a.title)
这意味着可以动态构建查询:
def search_articles(keyword=None, category_id=None, min_views=0):
qs = Article.objects.filter(status="published")
if keyword:
qs = qs.filter(title__icontains=keyword)
if category_id:
qs = qs.filter(category_id=category_id)
if min_views > 0:
qs = qs.filter(views__gte=min_views)
return qs.order_by("-created_at")
步骤 3:Q 对象组合复杂条件
| 表示 OR,& 表示 AND,~ 表示 NOT:
from django.db.models import Q
# (status='published' AND views>100) OR title contains 'Django'
Article.objects.filter(
Q(status="published", views__gt=100) | Q(title__icontains="Django")
)
# 复杂嵌套
Article.objects.filter(
Q(status="published") &
(Q(author__username="alice") | Q(author__username="bob")) &
~Q(category__name="广告")
)