当前位置: 首页 > news >正文

Django 模型与 ORM 全解析(二):数据库操作

引言:为什么要学 Django ORM?

  • 什么是 Django ORM?—— 简化数据库操作的 “桥梁”,它允许开发者使用 Python 语法而非原生 SQL 与数据库交互,无需关注底层数据库类型的差异。
  • 学习目标:掌握 ORM 核心增删改查(CRUD)及进阶用法,高效完成数据库操作。
  • 博客结构:从基础到高级,从核心操作到扩展技巧,逐步拆解 ORM 实用方法。

一、查询操作(Read)

查询是 ORM 最常用的操作,Django 提供基础查询和高级查询两类方法,满足不同场景的需求。

1.1 基本查询

基本查询用于获取单个或多个符合条件的记录,核心方法如下:

方法描述适用场景
all()获取所有记录(返回QuerySet)列表页展示所有数据
get (条件)获取单个符合条件的记录(返回实例)根据主键 / 唯一字段获取单条数据
filter (条件)获取多个符合条件的记录(返回 QuerySet)按条件筛选数据(如状态 = 激活)
exclude (条件)排除符合条件的记录(返回 QuerySet)筛选 “不满足条件” 的数据

代码示例:

# 获取所有对象 
Model.objects.all() # 根据条件获取单个对象 
Model.objects.get(id=1) # 根据条件过滤对象 
Model.objects.filter(name='example') # 排除特定条件的对象 
Model.objects.exclude(status='inactive')

注意:

  • get(条件)若未找到记录或找到多条记录,会抛出异常(DoesNotExistMultipleObjectsReturned,需谨慎使用。
  • 若需 “安全获取单个记录”,可结合get_or_create()(后续创建操作介绍)。

1.2 高级查询

高级查询是在基本查询的基础上,实现排序、限制结果、判断存在性等功能:

  1. 链式查询:将多个查询方法串联,实现多条件筛选(QuerySet 支持链式调用):

    # 筛选“作者为张三”且“状态为激活”的图书
    books = Book.objects.filter(author='张三').exclude(is_active=False)
    
  2. 排序:通过order_by(字段)实现排序,字段前加 “-” 表示降序:

    # 按出版日期升序(旧→新)
    books = Book.objects.order_by('publication_date')
    # 按出版日期降序(新→旧)
    books = Book.objects.order_by('-publication_date')
    
  3. 限制结果数量:通过切片[:n]获取前 n 条记录(类似 Python 列表切片,不支持负索引):

    # 获取前5条图书记录(用于分页或列表页默认展示)
    books = Book.objects.all()[:5]
    
  4. 判断是否存在:通过exists()判断是否有符合条件的记录,返回布尔值(比len()更高效,无需加载所有数据):

    # 判断是否存在“作者为张三”的图书
    has_zhang_books = Book.objects.filter(author='张三').exists()
    print(has_zhang_books)  # 存在返回True,不存在返回False
    
  5. 数量统计:通过count()统计符合条件的记录数,返回整数(比len(QuerySet)更高效,直接执行COUNT(*) SQL):

    # 统计所有图书数量
    total_books = Book.objects.count()
    # 统计“激活状态”的图书数量
    active_books_count = Book.objects.filter(is_active=True).count()

二、 创建操作(Create)

创建操作用于向数据库插入新记录,Django 提供单个创建和批量创建两种方式。

2.1 单个对象创建

单个对象创建有三种常用方法,适用于不同场景:

  1. 方法 1:先实例化再保存(分步操作,可在保存前修改字段):

    # 1. 实例化模型(未保存到数据库)
    book = Book(title='Django 5教程', author='张三', price=99.99)
    # 2. (可选)修改字段
    book.publication_date = '2024-05-01'
    # 3. 保存到数据库(执行INSERT SQL)
    book.save()
    
  2. 方法 2:直接创建(一步完成,通过objects.create()):

    # 直接创建并保存到数据库,返回创建的实例
    book = Book.objects.create(title='Django 5教程',author='张三',price=99.99,publication_date='2024-05-01'
    )
    
  3. 方法 3:获取或创建(避免重复创建,通过objects.get_or_create()):若记录已存在,则获取;若不存在,则创建,返回(实例, 是否创建成功)的元组:

    # 根据title查询,若不存在则创建(defaults为创建时的其他字段)
    book, created = Book.objects.get_or_create(title='Django 5教程',  # 查询条件(需是唯一字段或组合唯一)defaults={'author': '张三','price': 99.99,'publication_date': '2024-05-01'}
    )
    print(created)  # 第一次创建返回True,后续获取返回False

2.2 批量创建:bulk_create ()

若需创建多条记录,使用bulk_create()比循环调用create()更高效(仅执行一次 SQL,减少数据库连接次数):

# 1. 构建多个模型实例(未保存)
book_list = [Book(title='Django 5教程1', author='张三', price=99.99),Book(title='Django 5教程2', author='张三', price=89.99),Book(title='Django 5教程3', author='张三', price=79.99),
]
# 2. 批量保存到数据库
Book.objects.bulk_create(book_list)

三、更新操作(Update)

更新操作用于修改数据库中已有的记录,支持单个更新和批量更新。

3.1 单个对象更新

单个对象更新有三种方法,根据是否需要 “先获取实例” 选择:

方法 1:获取对象后修改字段→保存(适用于需先处理数据的场景):

# 1. 获取实例
book = Book.objects.get(id=1)
# 2. 修改字段
book.title = 'Django 5教程(第二版)'
book.price = 109.99
# 3. 保存到数据库(执行UPDATE SQL)
book.save()

方法 2:filter ()+update ()(直接更新,无需先获取实例,更高效):适用于明确条件、无需修改实例其他属性的场景,直接执行UPDATE SQL:

# 根据id更新title和price(无需获取实例)
Book.objects.filter(id=1).update(title='Django 5教程(第二版)',price=109.99
)

方法 3:更新或创建update_or_create(),不存在则创建):类似get_or_create(),但会更新已存在的记录,返回(实例, 是否创建成功)

# 根据id更新,若id=1不存在则创建
book, created = Book.objects.update_or_create(id=1,  # 查询条件(通常是主键)defaults={'title': 'Django 5教程(第二版)','price': 109.99}
)
print(created)  # 存在则更新,返回False;不存在则创建,返回True

3.2 批量更新:filter ().update ()

批量更新是对符合条件的所有记录执行统一更新,适用于 “批量修改状态” 等场景:

# 1. 批量将“待处理”状态的订单改为“已处理”
Order.objects.filter(status='pending').update(status='processed')# 2. 批量更新所有记录的“更新时间”为当前时间(需导入timezone)
from django.utils import timezone
Book.objects.all().update(updated_at=timezone.now())

四、删除操作(Delete)

删除操作用于从数据库中移除记录,支持单个删除和批量删除,操作需谨慎(删除后无法恢复)。

4.1 单个对象

删除单个对象删除有两种方法,与更新操作逻辑类似:

方法 1:获取对象后删除(适用于需先验证的场景):

# 1. 获取实例
book = Book.objects.get(id=1)
# 2. 删除记录(执行DELETE SQL)
book.delete()

方法 2:filter ().delete ()(直接删除,无需先获取实例):

# 根据id直接删除记录
Book.objects.filter(id=1).delete()

4.2 批量删除

批量删除是对符合条件的所有记录执行删除,需特别注意all().delete()(删除所有记录):

# 1. 批量删除“未激活”的图书
Book.objects.filter(is_active=False).delete()# 2. 删除所有图书(谨慎使用!会清空整个表)
Book.objects.all().delete()

五、其他常用 ORM 操作

除了 CRUD,Django ORM 还提供聚合查询、关联查询优化、原生 SQL 查询等高级功能,满足复杂业务需求。

5.1 聚合查询:Count、Sum、Avg、Max、Min

聚合查询用于对字段进行统计计算(如求和、平均值),需从django.db.models导入聚合函数,示例如下:

from django.db.models import Count, Sum, Avg, Max, Min# 1. 统计图书总数(等价于Book.objects.count())
total_books = Book.objects.aggregate(total=Count('id'))
print(total_books)  # 输出{'total': 100}(假设共100本)# 2. 计算所有图书的价格总和
total_price = Book.objects.aggregate(total=Sum('price'))
print(total_price)  # 输出{'total': Decimal('9999.99')}# 3. 计算图书的平均价格
avg_price = Book.objects.aggregate(avg=Avg('price'))
print(avg_price)  # 输出{'avg': Decimal('99.99')}# 4. 获取图书的最高价格和最低价格
price_extremes = Book.objects.aggregate(max=Max('price'),min=Min('price')
)
print(price_extremes)  # 输出{'max': Decimal('199.99'), 'min': Decimal('29.99')}

5.2 关联查询优化:select_related 与 prefetch_related

关联查询若不优化,会产生 “N+1 查询问题”(如查询 10 本书,先查 10 本图书,再查每本的作者,共执行 11 次 SQL)。Django 提供两种优化方法:

1.select_related:用于 “一对一” 或 “多对一”(ForeignKey)关联,一次性加载关联对象(左连接),适用于 “正向关联查询”:

# 优化前:查询10本书,会执行1(查图书)+10(查每本的作者)=11次SQL
books = Book.objects.all()[:10]
for book in books:print(book.author.name)  # 每次循环都执行一次查作者的SQL# 优化后:仅执行1次SQL,一次性加载图书和关联的作者
books = Book.objects.select_related('author').all()[:10]
for book in books:print(book.author.name)  # 无需额外执行SQL

2.prefetch_related:用于 “多对多” 或 “一对多反向查询”,先查询主对象,再批量查询关联对象(两次 SQL),适用于 “反向关联或多对多查询”:

# 优化前:查询10个作者,执行1(查作者)+10(查每个作者的图书)=11次SQL
authors = Author.objects.all()[:10]
for author in authors:print(author.book_set.all())  # 每次循环执行一次查图书的SQL# 优化后:仅执行2次SQL(先查作者,再批量查所有作者的图书)
authors = Author.objects.prefetch_related('book_set').all()[:10]
for author in authors:print(author.book_set.all())  # 无需额外执行SQL

5.5.3 原生 SQL 查询:raw () 与 extra ()

若 ORM 查询无法满足复杂需求(如多表联查、自定义函数),可通过原生 SQL 查询直接执行 SQL 语句:

1.raw():执行原生 SELECT 语句,返回RawQuerySet(可迭代的模型实例):

# 执行原生SQL,查询id=1的图书(参数用%s占位,避免SQL注入)
books = Book.objects.raw('SELECT * FROM book WHERE id = %s', [1])
# 迭代获取结果(RawQuerySet是惰性的,仅在迭代时执行SQL)
for book in books:print(book.title)

2.extra():在 ORM 查询的基础上,添加额外的 SQL 条件(如 WHERE、SELECT),适用于简单的原生 SQL 补充:

# 添加额外的WHERE条件:查询标题包含“Django”的图书
books = Book.objects.extra(where=["title LIKE %s"],  # SQL条件(占位符%s)params=['%Django%']       # 参数(自动转义,避免注入)
)# 添加额外的SELECT字段:查询图书并计算“折扣价”(假设discount=20)
books = Book.objects.extra(select={'discount_price': 'price * 0.8'}  # 自定义SELECT字段
)
for book in books:print(book.discount_price)  # 访问自定义字段

附录:Django ORM 常用方法速查表

CRUD 核心方法对比表

方法分类方法名语法示例用途适用场景
查询all()Model.objects.all()获取所有数据数据列表展示
查询get()Model.objects.get(id=1)获取单个唯一数据按主键查询详情
创建create()Model.objects.create(name='test')单个对象创建新增单条数据
创建bulk_create()Model.objects.bulk_create([obj1, obj2])批量对象创建批量导入数据
更新update()Model.objects.filter(id=1).update(name='new')批量 / 单个字段更新无需触发 save() 时
删除delete()Model.objects.filter(id=1).delete()批量 / 单个对象删除移除指定条件数据

聚合 / 关联查询关键 API 汇总

查询类型核心 API适用关系作用
聚合查询Count/Sum单表数据统计计算记录数、总和等
关联查询select_related()一对一、一对多连表预加载关联数据
关联查询prefetch_related()多对多、反向一对多预加载关联数据,避免 N+1 查询
http://www.dtcms.com/a/395693.html

相关文章:

  • Python 2025:AI与自动化运维的融合新纪元
  • MySQL 核心函数与约束详解
  • 设计模式简要
  • 服务扩容与容量评估手册
  • Pyside6 + QML - 信号与槽08 - 一个函数被多个信号触发(带参数)
  • 【第十一章】Python 调用 MySQL 全面指南:从基础到实践​
  • 新手玩家如何使用云手机
  • 【Datawhale组队学习202509】AI硬件与机器人大模型 task02 视觉感知与手眼协调
  • 基础算法---【前缀和】
  • YOLO系统——yolov1工作原理
  • 第20讲 机器学习中的分类数据
  • 《前端学习总结:GitLab、状态管理、组件库与 Umi.js》
  • 【论文阅读】理解世界还是预测未来?—— 世界模型全面综述
  • AR眼镜:远程协作与精准操作的未来之眼
  • 【论文阅读】GR-2:用于机器人操作的生成式视频-语言-动作模型
  • maven GAVP 的含义
  • 【Android】录制视频
  • RK3576-Android15_Usb白名单功能实现篇二
  • Spring中使用Apache Http客户端调第三方系统接口临时查看请求体参数
  • Linux系统-debian系的软件包管理
  • PCB工艺中的深微孔
  • 关于Pycharm中在运行出现语法错误:Non-UTF-8 code starting with
  • 构建AI智能体:四十一、大模型思维链提示工程:技术原理与行业应用案例分析
  • 鸿蒙系统中音视频的采集与播放
  • HTTPS 双向认证抓包实战,原理、难点、工具与可操作的排查流程
  • 开源跨平台文件管理工具,告别杂乱无章的数据世界
  • Node.js事件循环机制
  • Linux---文件系统
  • 循环语句效率与规范的原理及示例解析
  • Three.js 开发实战教程(四):相机系统全解析与多视角控制