引言
Django ORM是开发者与数据库交互的核心工具,通过对象化操作替代复杂SQL,极大提升开发效率。然而,其功能远不止基础的增删改查。本文将基于官方文档与实战经验,系统梳理Django ORM全流程,涵盖模型定义、字段详解、查询优化、事务管理及原生SQL整合,助你彻底掌握ORM精髓!
目录
惰性执行:查询集仅在使用时执行SQL(如遍历、切片、序列化)。
一、Django ORM基础与配置
1.1 ORM核心概念
-
定义:对象关系映射(ORM)通过Python类与数据库表的映射,实现数据操作对象化。
-
作用:解耦业务逻辑与数据库,支持多数据库切换(如MySQL、PostgreSQL)。
1.2 MySQL数据库配
修改settings.py
:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'your_db', # 数据库名(需预先创建)
'USER': 'root', # 用户名
'PASSWORD': '123456', # 密码
'HOST': 'localhost', # 数据库IP
'PORT': '3306', # 端口
}
}
初始化配置:在项目__init__.py
中加载MySQL驱动:
import pymysql
pymysql.install_as_MySQLdb()
迁移数据库:
python manage.py makemigrations
python manage.py migrate
1.3 启用SQL日志(调试必备)
在settings.py
中添加日志配置,实时查看ORM生成的SQL:
LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'handlers': {
'console': {
'level': 'DEBUG',
'class': 'logging.StreamHandler',
},
},
'loggers': {
'django.db.backends': {
'handlers': ['console'],
'level': 'DEBUG',
},
}
}
二、模型与字段深度解析
2.1 模型定义规则
-
每个模型对应一张数据库表,继承自
django.db.models.Model
。 -
示例:定义一个
Book
模型:
class Book(models.Model):
title = models.CharField(max_length=100, verbose_name="书名")
publish_date = models.DateField(auto_now_add=True, verbose_name="出版日期")
price = models.DecimalField(max_digits=6, decimal_places=2, verbose_name="价格")
publisher = models.ForeignKey('Publisher', on_delete=models.CASCADE, verbose_name="出版社")
2.2 常用字段类型大全
字段类型 | 说明 |
---|---|
AutoField | 自增主键,需设置primary_key=True |
CharField | 字符串,必须指定max_length |
IntegerField | 整数(范围:-2147483648~2147483647) |
DecimalField | 高精度小数,需指定max_digits (总位数)和decimal_places (小数位) |
ForeignKey | 外键关联,on_delete 指定删除策略(如CASCADE 级联删除) |
ManyToManyField | 多对多关联,可通过through 自定义中间表 |
DateTimeField | 日期时间,支持auto_now (修改时更新)和auto_now_add (创建时更新) |
2.3 字段参数详解
参数 | 说明 |
---|---|
null=True | 允许数据库字段为NULL |
default=0 | 字段默认值 |
unique=True | 字段值唯一 |
db_index=True | 为字段创建索引,加速查询 |
choices=[(0, '男')] | 限制字段值为预设选项,适用于状态、类型等字段 |
三、ORM基础操作:增删改查
3.1 增加数据
方法1:create()
直接创建
Book.objects.create(title="Python入门", price=59.9, publisher_id=1)
方法2:实例化后保存
book = Book(title="Django实战", price=89.9, publisher_id=2)
book.save()
3.2 删除数据
删除符合条件的记录:
Book.objects.filter(price__lt=30).delete() # 删除价格低于30的书籍
3.3 修改数据
批量更新:
Book.objects.filter(publisher__name="清华社").update(price=F('price') * 0.9) # 打9折
单条更新:
book = Book.objects.get(id=1)
book.title = "Python进阶"
book.save()
3.4 查询数据
全量查询:
all_books = Book.objects.all()
条件查询:
cheap_books = Book.objects.filter(price__lte=50) # 价格≤50
recent_books = Book.objects.exclude(publish_date__year=2020) # 排除2020年出版
3.5 查询集(QuerySet)特性
-
惰性执行:查询集仅在使用时执行SQL(如遍历、切片、序列化)。
-
链式调用:支持多次过滤与排序:
books = Book.objects.filter(price__gt=50).order_by('-publish_date')[:10] # 价格>50且按日期倒序取前10
四、高级查询与关联操作
4.1 聚合与分组
聚合函数(aggregate
):
from django.db.models import Avg, Max
result = Book.objects.aggregate(
avg_price=Avg('price'),
max_price=Max('price')
) # 输出:{'avg_price': 65.0, 'max_price': 99.9}
分组统计(annotate
):
from django.db.models import Count
# 按出版社分组统计书籍数量
publishers = Publisher.objects.annotate(book_count=Count('book')).values('name', 'book_count')
4.2 F查询:字段间比较与运算
比较字段值:
from django.db.models import F
# 查询库存小于销量的书籍
Book.objects.filter(stock__lt=F('sales'))
字段运算:
# 将所有书籍价格增加10元
Book.objects.all().update(price=F('price') + 10)
4.3 Q查询:复杂逻辑组合
OR查询:
from django.db.models import Q
# 查询书名含“Python”或价格低于50的书籍
Book.objects.filter(Q(title__icontains="Python") | Q(price__lt=50))
NOT查询:
# 查询非2020年出版且书名不含“基础”的书籍
Book.objects.filter(~Q(publish_date__year=2020) & ~Q(title__icontains="基础"))
4.4 关联查询:跨表操作
正向查询:
book = Book.objects.first()
publisher_name = book.publisher.name # 获取书籍关联的出版社名称
反向查询:
publisher = Publisher.objects.get(name="清华社")
books = publisher.book_set.all() # 获取该出版社所有书籍
4.5 多对多关系操作
添加关联:
author = Author.objects.get(id=1)
book.authors.add(author) # 将作者关联到书籍
清空关联:
book.authors.clear() # 移除所有关联作者
五、事务与原生SQL
5.1 事务管理
使用transaction.atomic()
确保操作原子性:
from django.db import transaction
try:
with transaction.atomic():
# 减少库存并生成订单
book = Book.objects.select_for_update().get(id=1)
book.stock -= 1
book.save()
Order.objects.create(book=book, user=request.user)
except Exception as e:
print(f"操作失败:{e}")
5.2 执行原生SQL
from django.db import connection
with connection.cursor() as cursor:
cursor.execute("SELECT * FROM app_book WHERE price > %s", [100])
rows = cursor.fetchall() # 获取所有结果
# 使用extra扩展查询
Book.objects.extra(
where=["CHAR_LENGTH(title) > 10"], # 标题长度大于10字符
select={'price_tax': 'price * 1.1'} # 计算含税价格
)