Django ORM


广州飞领
阿里波波 发布于 2026-01-07 / 1 阅读 / 0 评论 /
ORM 的全名是 Object-Relational Mapping(对象关系映射)。 简单来说,就是把数据库的表映射成Python 对象,把字段映射成对象属性,这样你就可以用 Python 代码操作数据库,而不用写 SQL。 🎯 不用 ORM 的时代是这样的 # 直接写 SQLcursor.ex

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 的真正价值在于:

  1. 代码更安全 - 自动防止 SQL 注入
  2. 开发更快速 - 少写 80% 的 SQL 代码
  3. 维护更简单 - 数据库迁移变得超简单
  4. 思维更清晰 - 面向对象编程,不用关心 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 个你必须记住的点

  1. ORM 不是魔法,但能帮你写更安全、更快速的代码 - 学会用 ORM,你的代码质量会上一个台阶
  2. 性能优化从 ORM 开始 - prefetch_related 和 select_related 是你最好的朋友,学会用它们能 10 倍提升性能
  3. 不要畏惧复杂查询 - 大多数复杂的需求,ORM 都能解决,别急着写原生 SQL


是否对你有帮助?

评论