ORM 的全名是 Object-Relational Mapping(对象关系映射)。
简单来说,就是把数据库的表映射成Python 对象,把字段映射成对象属性,这样你就可以用 Python 代码操作数据库,而不用写 SQL。
🎯 不用 ORM 的时代是这样的
# 直接写 SQLcursor.execute("""
SELECT * FROM users
WHERE age >= 18
AND status = 'active'
ORDER BY created_at DESC
LIMIT 10
""")
users = cursor.fetchall()
这样做的坑很多:
- ❌ 容易 SQL 注入(安全风险)
- ❌ 代码分散,容易维护混乱
- ❌ 换个数据库(比如从 MySQL 改 PostgreSQL)就要全改 SQL
- ❌ 复杂查询容易出 Bug
✅ 用 ORM 是这样的
# 用 Django ORM,一行代码搞定
users = User.objects.filter(age__gte=18, status='active').order_by('-created_at')[:10]
看到区别了吗?
Django ORM 的真正价值在于:
- 代码更安全 - 自动防止 SQL 注入
- 开发更快速 - 少写 80% 的 SQL 代码
- 维护更简单 - 数据库迁移变得超简单
- 思维更清晰 - 面向对象编程,不用关心 SQL 细节
📝 怎么用 Django ORM?核心用法讲解
把 ORM 最常用的 5 种操作归纳出来,掌握这 5 个,你就能解决 80% 的问题。
1️⃣ 基础查询(CREATE & READ)
# 1. 创建数据
user = User.objects.create(name="Jack", age=25, status='active')
# 2. 查询所有
all_users = User.objects.all()
# 3. 查询单条
user = User.objects.get(id=1) ?# 如果没找到会报错
# 4. 查询单条(安全方式)
user = User.objects.filter(id=1).first() ?# 没找到返回 None
# 5. 条件查询(最重要!)
users = User.objects.filter(age__gte=18, status='active')
# age__gte 表示 age >= 18
# status='active' 就是 status = 'active'
2️⃣ 复杂查询(关键知识点)
# Q 对象用于复杂逻辑(AND 和 OR)
from django.db.models import Q
# OR 查询:年龄 > 18 或状态为 'admin'
users = User.objects.filter(Q(age__gt=18) | Q(status='admin'))
# AND 查询:年龄 > 18 且状态为 'active'
users = User.objects.filter(Q(age__gt=18) & Q(status='active'))
# NOT 查询:排除某些数据
users = User.objects.exclude(status='inactive')
3️⃣ 聚合查询(一句代码搞定统计)
from?django.db.models import Count, Sum, Avg
# 统计用户总数
total = User.objects.count()
# 统计平均年龄
avg_age = User.objects.aggregate(Avg('age'))['age__avg']
# 按状态分组统计
stats = User.objects.values('status').annotate(count=Count('id'))
# 结果:[{'status': 'active', 'count': 150}, {'status': 'inactive', 'count': 50}]
4️⃣ 关联查询(最能节省代码的地方)
在电影商城项目中,我们经常需要查询"某个用户的所有订单和订单详情"。
# Model 定义
class User(models.Model):
name = models.CharField(max_length=100)
class Order(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
total_price = models.DecimalField()
class OrderItem(models.Model):
order = models.ForeignKey(Order, on_delete=models.CASCADE)
movie = models.ForeignKey('Movie', on_delete=models.CASCADE)
price = models.DecimalField()
# 错误做法:N+1 查询问题(性能极差)
user = User.objects.get(id=1)
orders = user.order_set.all() # 查询 1 次
for order in orders:
items = order.orderitem_set.all() # 每个订单都查询 1 次!如果有 100 个订单,就是 101 次查询
# 正确做法:prefetch_related(性能提升 10 倍)
user = User.objects.prefetch_related('order_set__orderitem_set').get(id=1)
orders = user.order_set.all() # 只查询 3 次(user, orders, items)
for order in orders:
items = order.orderitem_set.all() # 直接读内存,不再查询数据库
5️⃣ 更新和删除
# 更新方式 1:修改单条
user = User.objects.get(id=1)
user.age = 26
user.save()
# 更新方式 2:批量更新(更高效)
User.objects.filter(status='inactive').update(status='active')
# 删除单条
user = User.objects.get(id=1).delete()
# 批量删除
User.objects.filter(age__lt=18).delete()
📊 实战案例:电影商城项目的真实对比
我在做电影商城项目时,遇到这样一个需求:
“统计每个电影的销售金额排行,只显示销售额超过 10000 元的电影,按销售额倒序排列”
❌ 如果用原生 SQL(我新手时候的做法)
SELECT
m.id, m.name, m.image,
COUNT(oi.id) as sale_count,
SUM(oi.price) as total_sales
FROM movie m
LEFT JOIN order_item oi ON m.id = oi.movie_id
LEFT JOIN orders o ON oi.order_id = o.id
WHERE o.status = 'completed'
GROUP BY m.id, m.name, m.image
HAVING SUM(oi.price) > 10000
ORDER BY total_sales DESC
LIMIT 20
我写了 15 分钟,代码容易出 Bug,而且很难维护。
✅ 用 Django ORM(现在的做法)
from django.db.models import Sum, Count
movies = Movie.objects.annotate(
total_sales=Sum('orderitem__price'),
sale_count=Count('orderitem')
).filter(
total_sales__gt=10000,
orderitem__order__status='completed'
).order_by('-total_sales')[:20]
# 取数据时
for movie in movies:
print(f"{movie.name}: {movie.total_sales} 元,{movie.sale_count} 件")
🎯 那些容易踩的坑,我都帮你总结了
坑 1️⃣:忽视 N+1 查询问题
# ❌ 坑
for order in Order.objects.all():
print(order.user.name) # 每条 order 都会查询一次 user
# ✅ 正确
for order in Order.objects.select_related('user'):
print(order.user.name) # 只查询 2 次
规则: 一对一和外键关系用 select_related(),多对多和反向外键用 prefetch_related()。
坑 2️⃣ :字段查询的特殊语法
很多人不懂 age__gte 这样的语法,以为是拼写错误。实际上这是 Django ORM 的查询语法:
# 常用的查询表达式
age__gte=18 # age >= 18
age__lte=18 # age <= 18
age__gt=18 # age > 18
age__lt=18 # age < 18
name__contains='a' # name 包含 'a'
name__startswith='J' # name 以 'J' 开头
created_at__year=2026 # 年份是 2026
坑 3️⃣:update() vs 修改后 save()
# ❌ 如果要批量更新,不要这样做
users = User.objects.filter(status='inactive')
for user in users:
user.status = 'active'
user.save() # 执行 100 次数据库操作!
# ✅ 正确做法
User.objects.filter(status='inactive').update(status='active') # 只执行 1 次!
🚀 结尾:3 个你必须记住的点
- ORM 不是魔法,但能帮你写更安全、更快速的代码 - 学会用 ORM,你的代码质量会上一个台阶
- 性能优化从 ORM 开始 - prefetch_related 和 select_related 是你最好的朋友,学会用它们能 10 倍提升性能
- 不要畏惧复杂查询 - 大多数复杂的需求,ORM 都能解决,别急着写原生 SQL