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

Django ORM 详解

        在 Web 开发中,数据库操作是核心环节之一。传统的数据库操作需要编写复杂的 SQL 语句,不仅效率低,还容易出错。而 Django 的 ORM(Object-Relational Mapping,对象关系映射)技术,让开发者可以用面向对象的方式操作数据库,彻底摆脱 SQL 的束缚。本文将详细介绍 Django ORM 的核心概念、使用方法及高级技巧。

一、ORM 是什么?核心思想是什么?

ORM(Object-Relational Mapping)即对象关系映射,是连接数据库与面向对象编程的桥梁。它的核心思想是将数据库中的元素与面向对象模型中的元素建立对应关系,让开发者可以通过操作对象来实现数据库的 CRUD(增删改查)操作。

具体对应关系如下:

数据库概念面向对象模型说明
数据库(Database)项目(Project)一个 Django 项目通常对应一个数据库
表(Table)类(Class)数据库中的表结构通过模型类定义
字段(Field)类属性(Attribute)表中的字段对应类中的属性
记录(Record)实例(Instance)表中的一行数据对应类的一个实例对象

二、模型定义:用类描述数据库表

在 Django 中,ORM 的使用始于模型类(Model) 的定义。模型类本质是对数据库表结构的抽象,定义在models.py文件中,继承自django.db.models.Model

基本模型定义示例

# models.py
from django.db import modelsclass User(models.Model):# 自增主键(如果不定义,Django会自动生成id字段作为主键)id = models.AutoField(primary_key=True)# 用户名(字符串类型,最大长度32)name = models.CharField(max_length=32, verbose_name="用户名")# 密码(整数类型,实际项目中通常用CharField存储哈希值)pwd = models.IntegerField(verbose_name="密码")# 注册时间(自动添加创建时间)register_time = models.DateTimeField(auto_now_add=True, verbose_name="注册时间")class Meta:# 定义表名(不指定则默认用"应用名_类名"作为表名)db_table = "user"# 模型的中文显示名verbose_name = "用户"verbose_name_plural = verbose_name

常用字段类型

Django 提供了丰富的字段类型,覆盖大部分数据库字段需求:

  • AutoField:自增整数,通常作为主键
  • CharField:字符串(需指定max_length
  • IntegerField:整数
  • TextField:长文本(无长度限制)
  • DateTimeField:日期时间(auto_now_add=True表示创建时自动记录时间,auto_now=True表示更新时自动刷新)
  • BooleanField:布尔值(True/False)
  • ForeignKey:外键(用于多表关联,如models.ForeignKey(OtherModel, on_delete=models.CASCADE)
  • ManyToManyField:多对多关系

三、数据库迁移:让模型生效

定义好模型后,需要通过迁移命令将模型转换为数据库中的实际表结构。Django 的迁移机制会记录模型的每一次变更,确保数据库结构与模型保持一致。

核心迁移命令

  1. 记录模型变更(生成迁移文件)将模型中与数据库相关的操作(新增表、修改字段等)记录到migrations文件夹中:

python manage.py makemigrations

        2.执行迁移(同步到数据库)将迁移文件中的操作真正应用到数据库,生成或修改表结构:

python manage.py migrate

注意事项

  • 每次修改models.py中与数据库相关的代码(如新增字段、修改字段类型),都必须重新执行上述两个命令。
  • 迁移文件是项目的一部分,需纳入版本控制(如 Git),确保团队协作时数据库结构一致。
  • 如需查看迁移计划(不实际执行),可使用:
python manage.py sqlmigrate 应用名 迁移文件编号

四、ORM 核心操作:CRUD 实战

Django ORM 的核心是通过模型管理器(objects) 操作数据库。objects是模型类的默认管理器,封装了所有数据库交互方法,支持链式调用。

1. 查询操作(Read)

查询是数据库操作中最常用的场景,Django ORM 提供了丰富的查询方法。

基本查询
from myapp.models import User# 1. 获取所有记录(返回QuerySet对象,可迭代)
all_users = User.objects.all()# 2. 根据条件获取单个记录(条件不存在会抛DoesNotExist异常)
user = User.objects.get(id=1)  # 按主键查询
user = User.objects.get(name="张三")  # 按其他字段查询# 3. 按条件过滤记录(返回符合条件的QuerySet,支持多条件)
active_users = User.objects.filter(name="张三", pwd=123456)  # 多条件"且"
users_contain_li = User.objects.filter(name__contains="李")  # 模糊查询(name包含"李")# 4. 排除符合条件的记录
inactive_users = User.objects.exclude(name="张三")  # 排除name为"张三"的记录
高级查询
# 1. 链式查询(多个条件组合)
users = User.objects.filter(name__startswith="张").exclude(pwd=0).order_by("register_time")# 2. 排序(默认升序,字段前加"-"表示降序)
users_by_time_asc = User.objects.order_by("register_time")  # 按注册时间升序
users_by_time_desc = User.objects.order_by("-register_time")  # 按注册时间降序# 3. 判断记录是否存在(返回布尔值,比get()更安全)
has_zhang = User.objects.filter(name="张三").exists()# 4. 统计数量
total_users = User.objects.count()  # 总记录数
zhang_count = User.objects.filter(name__startswith="张").count()  # 符合条件的数量# 5. 只获取部分字段(返回字典列表)
user_names = User.objects.values("id", "name")  # [{"id":1, "name":"张三"}, ...]# 6. 获取单个字段列表(返回元组列表)
user_ids = User.objects.values_list("id", flat=True)  # [1, 2, 3, ...](flat=True返回一维列表)

2. 创建操作(Create)

创建操作用于向数据库插入新记录,Django 提供了多种创建方式。

单个对象创建
# 方法1:先实例化对象,再调用save()保存(适合需要先处理对象属性的场景)
user = User(name="李四", pwd=654321)
user.register_time = "2023-10-01 12:00:00"  # 可选:手动设置其他字段
user.save()  # 保存到数据库# 方法2:直接通过create()创建(一步到位,返回创建的对象)
user = User.objects.create(name="王五", pwd=111222)# 方法3:get_or_create(查询存在则返回,不存在则创建,避免重复)
user, created = User.objects.get_or_create(name="赵六",  # 查询条件defaults={"pwd": 333444}  # 若不存在,创建时的其他字段
)
# created为布尔值:True表示新创建,False表示查询到已存在
批量创建

批量创建比循环单个创建效率更高(减少数据库交互次数):

# 批量创建3个用户
users = [User(name="小明", pwd=123),User(name="小红", pwd=456),User(name="小刚", pwd=789)
]
User.objects.bulk_create(users)  # 批量插入

3. 更新操作(Update)

更新操作用于修改数据库中已有的记录。

单个对象更新
# 方法1:先查询对象,修改属性后save()(会更新所有字段,适合少量字段修改)
user = User.objects.get(id=1)
user.name = "张三_new"  # 修改字段
user.save()  # 保存更新# 方法2:通过filter()直接更新(只更新指定字段,效率更高)
User.objects.filter(id=1).update(name="张三_new2", pwd=999999)# 方法3:update_or_create(存在则更新,不存在则创建)
user, created = User.objects.update_or_create(id=1,  # 查询条件(按id查找)defaults={"name": "张三_updated", "pwd": 888888}  # 若存在则更新的字段
)
批量更新

批量更新符合条件的所有记录:

# 批量更新所有name为"张三"的用户密码
User.objects.filter(name="张三").update(pwd=000000)# 更新所有用户的注册时间为当前时间(需导入timezone)
from django.utils import timezone
User.objects.all().update(register_time=timezone.now())

4. 删除操作(Delete)

删除操作用于移除数据库中的记录,需谨慎使用(删除后不可恢复)。

单个对象删除
# 方法1:先查询对象,再调用delete()
user = User.objects.get(id=1)
user.delete()# 方法2:直接通过filter()删除(更简洁)
User.objects.filter(id=1).delete()
批量删除
# 删除所有name包含"测试"的用户
User.objects.filter(name__contains="测试").delete()# 删除所有记录(谨慎!会清空表)
User.objects.all().delete()

注意:如果模型有外键关联(如ForeignKey),删除时需注意on_delete参数的配置(如CASCADE表示级联删除,关联的子表记录也会被删除)。

五、高级查询技巧

除了基础 CRUD,Django ORM 还支持复杂查询场景,满足业务需求。

1. Q 对象:实现 "或" 条件查询

filter()默认是 "且" 条件,如需 "或" 条件,需使用Q对象:

from django.db.models import Q# 查询name为"张三"或pwd为123的用户
users = User.objects.filter(Q(name="张三") | Q(pwd=123))# 组合"且"和"或"(Q对象优先级高于普通条件)
users = User.objects.filter(Q(name="张三") | Q(pwd=123),register_time__gt="2023-01-01"  # 同时满足注册时间在2023年之后
)

2. F 对象:同表字段比较

F()用于引用模型中的字段,实现同一条记录的字段间比较:

from django.db.models import F# 查询pwd大于id的用户(假设业务中有此需求)
users = User.objects.filter(pwd__gt=F("id"))# 批量更新:将所有用户的pwd增加100
User.objects.all().update(pwd=F("pwd") + 100)

3. 聚合查询(aggregate)

用于对查询结果进行统计(如求和、平均值等):

from django.db.models import Sum, Avg, Max, Min# 统计所有用户pwd的总和、平均值、最大值、最小值
result = User.objects.aggregate(total_pwd=Sum("pwd"),avg_pwd=Avg("pwd"),max_pwd=Max("pwd"),min_pwd=Min("pwd")
)
# result格式:{"total_pwd": 12345, "avg_pwd": 1234.5, ...}

4. 分组查询(annotate)

结合聚合函数,按字段分组统计

from django.db.models import Count# 按name分组,统计每个name的用户数量
name_counts = User.objects.values("name").annotate(count=Count("id"))
# 结果:[{"name": "张三", "count": 2}, {"name": "李四", "count": 1}, ...]

六、ORM 查询优化

在数据量大的场景下,不合理的查询会导致性能问题,需注意优化。

1. 避免 N+1 查询问题

当查询关联表数据时(如查询用户及其关联的订单),直接循环查询会产生 N+1 次数据库请求(1 次查用户,N 次查每个用户的订单)。

解决方法:使用select_related(一对一 / 多对一关系)或prefetch_related(多对多 / 反向多对一关系)预加载关联数据。

# 假设User有一个外键关联到Order(多对一)
from myapp.models import Order# 优化前:查询用户及其订单(N+1问题)
users = User.objects.all()
for user in users:orders = user.order_set.all()  # 每个user都会触发一次查询# 优化后:用select_related预加载关联数据(1次查询)
users = User.objects.select_related("order").all()  # 假设外键字段是order

2. 只查询需要的字段

使用only()defer()减少查询字段,降低数据传输量:

# 只查询id和name字段(其他字段不加载)
users = User.objects.only("id", "name")# 排除pwd字段(加载其他所有字段)
users = User.objects.defer("pwd")

七、总结

        Django ORM 是 Django 框架的核心优势之一,它通过面向对象的方式封装了数据库操作,让开发者无需编写 SQL 即可完成 CRUD 及复杂查询。本文介绍了 ORM 的核心概念、模型定义、迁移命令、CRUD 操作及高级技巧,掌握这些内容可以极大提升数据库操作的效率。

        在实际开发中,建议结合 Django 官方文档深入学习 ORM 的细节(如多表关联、事务处理等),并注意查询优化,避免性能问题。

        希望本文对你理解 Django ORM 有所帮助,祝你的 Django 开发之旅更加顺畅!

http://www.dtcms.com/a/453389.html

相关文章:

  • C语言模拟面向对象编程方法之多态
  • 温州市建设工程管理网站温州建设网站哪家好
  • 划时代的技术飞跃:OpenAI DevDay 2025 全面深度解读
  • 做网站的网页图片素材怎么找长春做网站哪家便宜
  • 计算机操作系统:操作系统的发展过程
  • 未来之窗昭和仙君 (十三) 对话框组件— 东方仙盟筑基期
  • 茶叶公司网站建设策划书制作展示型网站公司哪家好
  • 部门定制网站建设公司免费电子版个人简历模板
  • 佛山营销网站建设咨询网站统计分析平台
  • 【工具变量】上市公司气候风险数据集(2011-2023年)
  • nat outbound acl-number address-group group-index 概念及题目
  • 电商网站构建预算方案门户网站html
  • CICD工具选型指南,Jenkins vs Arbess哪一款更好用?
  • 做彩票网站怎么样济南正规网站制作怎么选择
  • C++ 模板、泛型与 auto 关键字
  • 游戏项目 多态练习 超级玛丽demo8
  • 外企 BI 工具选型:从合规到落地
  • 医疗知识普及网站开发网站建立教学
  • Spring Boot中使用线程池来优化程序执行的效率!笔记01
  • 东平网站制作哪家好上海做网站站优云一一十七
  • 玩转ClaudeCode:通过Excel-MCP实现数据清洗并写入Excel
  • LeetCode 2761. 和等于目标值的质数对
  • 网站建设工作落实情况网站买流量是怎么做的
  • 开源 C++ QT QML 开发(九)文件--文本和二进制
  • 添加最新的LSKNet遥感目标检测网络主干
  • 融资网站开发湖南二维码标签品牌
  • 【开源】基于STM32的智能骑行头盔设计
  • 【Python刷力扣hot100】49. Group Anagrams
  • 招聘网站大全专业的企业进销存软件定制
  • 绿色学校网站模板高明网站建设报价