Django ORM

目录

1,基础语法

python 复制代码
# SELECT * FROM todo_demo_app_todo;
Todo.objects.all()

# SELECT id, name, is_done FROM todo_demo_app_todo;
Todo.objects.values('id', 'name', 'is_done')

# SELECT id, name FROM todo_demo_app_todo WHERE is_done = false;
Todo.objects.filter(is_done=False).values('id', 'name')

2,Where 条件查询

python 复制代码
# 等于: WHERE name = 'task'
Todo.objects.filter(name='task')

# 不等于: WHERE name != 'task' 或 WHERE name <> 'task'
Todo.objects.exclude(name='task')

# 大于: WHERE priority > 'low'
Todo.objects.filter(priority__gt='low')

# 小于等于: WHERE created_at <= '2023-01-01'
Todo.objects.filter(created_at__lte='2023-01-01')

# AND: WHERE name LIKE '%work%' AND is_done = false
Todo.objects.filter(name__icontains='work', is_done=False)

# OR: WHERE name LIKE '%work%' OR priority = 'high'
from django.db.models import Q
Todo.objects.filter(
    Q(name__icontains='work') | Q(priority='high')
)

# NOT: WHERE NOT (is_done = true)
Todo.objects.exclude(is_done=True)

3,模糊匹配查询

python 复制代码
# LIKE '%value%': WHERE name LIKE '%task%'
Todo.objects.filter(name__icontains='task')

# LIKE 'value%': WHERE name LIKE 'task%'
Todo.objects.filter(name__istartswith='task')

# LIKE '%value': WHERE name LIKE '%end'
Todo.objects.filter(name__iendswith='end')

# 区分大小写版本
Todo.objects.filter(name__contains='Task')  # 区分大小写
Todo.objects.filter(name__startswith='Task')
Todo.objects.filter(name__endswith='End')

4,范围查询 BETWEEN和IN

python 复制代码
# BETWEEN: WHERE id BETWEEN 1 AND 10
Todo.objects.filter(id__range=[1, 10])

# IN: WHERE priority IN ('high', 'medium')
Todo.objects.filter(priority__in=['high', 'medium'])

# NOT IN: WHERE priority NOT IN ('low', 'none')
Todo.objects.exclude(priority__in=['low', 'none'])

5,空值处理

python 复制代码
# IS NULL: WHERE description IS NULL
Todo.objects.filter(description__isnull=True)

# IS NOT NULL: WHERE description IS NOT NULL
Todo.objects.filter(description__isnull=False)

# 或者使用exclude
Todo.objects.exclude(description__isnull=True)

6,聚合函数

python 复制代码
from django.db.models import Count, Sum, Avg, Max, Min

# COUNT(*): SELECT COUNT(*) FROM todo_demo_app_todo
total_count = Todo.objects.count()

# COUNT with GROUP BY: SELECT priority, COUNT(*) FROM todo group by priority
priority_counts = Todo.objects.values('priority').annotate(count=Count('id'))

# MAX/MIN: SELECT MAX(created_at) FROM todo
latest_todo = Todo.objects.aggregate(Max('created_at'))
earliest_todo = Todo.objects.aggregate(Min('created_at'))

# AVG: SELECT AVG(length(name)) FROM todo
avg_name_length = Todo.objects.extra(select={'name_len': 'LENGTH(name)'}).aggregate(Avg('name_len'))

7,分组查询

python 复制代码
# 基础分组
# GROUP BY priority: SELECT priority, COUNT(*) FROM todo GROUP BY priority
grouped_by_priority = Todo.objects.values('priority').annotate(
    count=Count('id')
)

# 多字段分组: GROUP BY user, priority
grouped_multi = Todo.objects.values('user', 'priority').annotate(
    count=Count('id'),
    avg_priority=Avg(Case(
        When(priority='high', then=Value(3)),
        When(priority='medium', then=Value(2)),
        When(priority='low', then=Value(1)),
        default=Value(0),
        output_field=IntegerField()
    ))
)

# GROUP BY + HAVING: SELECT user, COUNT(*) FROM todo GROUP BY user HAVING COUNT(*) > 5
users_with_many_todos = Todo.objects.values('user').annotate(
    count=Count('id')
).filter(count__gt=5)

8,排序

python 复制代码
# ORDER BY created_at ASC
Todo.objects.order_by('created_at')

# ORDER BY created_at DESC
Todo.objects.order_by('-created_at')

# 多字段排序: ORDER BY priority DESC, created_at ASC
Todo.objects.order_by('-priority', 'created_at')

9,限制结果

python 复制代码
# LIMIT 10: SELECT * FROM todo LIMIT 10
first_ten = Todo.objects.all()[:10]

# OFFSET 10 LIMIT 5: SELECT * FROM todo OFFSET 10 LIMIT 5
offset_few = Todo.objects.all()[10:15]

# 使用Paginator进行分页
from django.core.paginator import Paginator
paginator = Paginator(Todo.objects.all(), 20)  # 每页20条
page_obj = paginator.get_page(1)  # 第一页

10,关联查询

内连接:查询的两张表的交集,及表A和表B都拥有的数据;

左连接:左边表的数据会全部显示出来,右边只会列出 on 后面条件符合的数据拼接在左边表,无数据补 null;

右连接:右边表的数据会全部显示出来,左边只会列出on 后面条件符合的数据拼接在右边表,无数据补 null;

全连接:左右表都会显示出来,on后面条件符合的字段会重叠

python 复制代码
# 内连接 INNER JOIN

# INNER JOIN: SELECT * FROM todo t JOIN user u ON t.user_id = u.id
todos_with_users = Todo.objects.select_related('user')

# 多重关联
todos_with_users_and_categories = Todo.objects.select_related('user', 'category')

# 左外连接(LEFT JOIN)
# LEFT JOIN: SELECT * FROM todo t LEFT JOIN comment c ON t.id = c.todo_id
todos_with_comments = Todo.objects.prefetch_related('comments')

# 预加载多个关系
complex_query = Todo.objects.select_related('user').prefetch_related('tags', 'comments')

11,子查询

Django ORM 子查询是指在一个查询(外查询)中嵌套另一个查询(内查询),将内查询的结果作为外查询的过滤条件或值,通过 Subquery``OuterRef;

python 复制代码
from django.db.models import OuterRef, Subquery

# 获取每个用户的最新订单
latest_order_subquery = Order.objects.filter(user=OuterRef('pk')).order_by('-create_time').values('amount')[:1]
user_with_last_order_amount = User.objects.annotate(latest_order_amount=Subquery(latest_order_subquery))
   for u in user_with_last_order_amount:
      print(f"用户: {u.name}, 最新订单金额: {u.latest_order_amount}")

# filter(user=OuterRef('pk)) OuterRef('pk') 代表"外层查询(即 User 查询)中当前行的主键 ID"。意思是:"找出订单表Order中,user_id 等于当前用户 ID 的那些订单"。
# order_by('-create_time'):按下单时间倒序排列(最新的排在前面)
# values('amount')[:1]:只取第一条记录(也就是最新的那笔订单)的 amount 字段。
# annotate:这是 Django ORM 的"注解"功能。它不会修改数据库表结构,而是在查询结果集中为每个对象临时附加一个计算出的字段。

12,CASE WHEN 语句

作用:在查询订单时,动态生成一个包含中文状态描述的新字段,以便直接用于前端展示

python 复制代码
from django.db.models import Case, When, Value

orders_with_status = Order.objects.annotate(
    status_display=Case(
        When(status='pending', then=Value('待支付')),
        When(status='paid', then=Value('已支付')),
        When(status='shipped', then=Value('已发货')),
        When(status='completed', then=Value('已完成')),
        When(status='cancelled', then=Value('已取消')),
        default=Value('未知'),
        output_field=CharField() # 告诉 django 这个计算结果是一个字符类型字段
    )
)
for order in orders_with_status:
    print(f"订单号: {order.order_no}")
    print(f"原始状态: {order.status}")       
    print(f"显示状态: {order.status_display}") 

# 输出结果
订单号: ORD202310010001
原始状态: paid
显示状态: 已支付

13,日期时间查询

python 复制代码
from datetime import datetime, timedelta

# DATE(): WHERE DATE(created_at) = '2023-01-01'
today_todos = Todo.objects.filter(created_at__date=datetime.now().date())

# DATE_SUB(): WHERE created_at >= NOW() - INTERVAL 7 DAY
recent_todos = Todo.objects.filter(
    created_at__gte=datetime.now() - timedelta(days=7)
)

# YEAR(), MONTH(), DAY(): WHERE YEAR(created_at) = 2023
year_2023_todos = Todo.objects.filter(created_at__year=2023)
month_todos = Todo.objects.filter(created_at__month=12)
day_todos = Todo.objects.filter(created_at__day=25)

14,性能优化

python 复制代码
# 使用only()和defer()优化字段加载
# SELECT id, name FROM todo (只获取必要字段)
minimal_data = Todo.objects.only('id', 'name')

# 排除大字段
without_large_fields = Todo.objects.defer('description', 'content')

# 使用values/values_list获取原始数据
# 查询Todo表,返回一个包含元组的列表,类似 [(1,'代办事项1'),(2,'代办事项2')]
# flat = True 如果你只查询一个字段,可以使用这个属性返回一个扁平的值列表,而不是元组列表,类型[1,2,3,4]
raw_data = Todo.objects.values_list('id', 'name', flat=True)  

values() 返回的是字典,DRF的serializer可以兼容字典输入,类似 [{'id': '...', 'name': ...}, ...]
相关推荐
IvanCodes1 小时前
四、Scala深入面向对象:类、对象与伴生关系
开发语言·后端·scala
嗯.~1 小时前
scala的泛型应用场景
开发语言·后端·scala
武雄(小星Ai)1 小时前
微软自研七款MAI模型,35B参数对标Claude Opus,零OpenAI蒸馏
人工智能·后端·agent
明月_清风1 小时前
图解 Socket 编程:一文吃透 TCP/UDP 编程模型(Go 实战版)
后端·tcp/ip·go
普通网友1 小时前
【python】pyspark.errors.exceptions.base.PySparkRuntimeError [JAVA_GATEWAY_EXITED] Java gateway proce
java·python·gateway
zavoryn1 小时前
Python 面试高频:装饰器、迭代器、生成器和上下文管理器一次讲清
开发语言·python·面试
YJlio1 小时前
OpenClaw v2026.5.26-beta.1 / beta.2 预发布解读:Gateway 加速、transcript 路径统一、多通道修复、语音增强与安装更新链路加固
人工智能·windows·python·ui·缓存·gateway·outlook
许彰午10 小时前
14_Java泛型完全指南
java·windows·python
智慧物业老杨10 小时前
司法绿色通道下的物业纠纷数智化解决方案——基于“三优先“机制的全流程技术落地实践
java·django