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

django-3模型操作

from django.db import modelsclass Book(models.Model):title = models.CharField(max_length=200)  # 书名author = models.CharField(max_length=100)  # 作者publish_date = models.DateField()  # 出版日期price = models.DecimalField(max_digits=10, decimal_places=2)  # 价格stock = models.IntegerField(default=0)  # 库存,默认0def __str__(self):return self.title

创建对象

save

# 1. 创建实例
book = Book(title="Django 入门",author="张三",publish_date=date(2023, 1, 1),price=59.99,stock=100
)# 2. 保存到数据库
book.save()  # 执行 INSERT 语句

create

直接创建并保存,返回创建的实例:

book = Book.objects.create(title="Python 编程",author="李四",publish_date=date(2022, 5, 10),price=49.99,stock=50
)

bulk_create

高效创建多条记录(仅执行一次 SQL):

books = [Book(title="Java 实战", author="王五", publish_date=date(2021, 3, 15), price=69.99, stock=30),Book(title="JavaScript 指南", author="赵六", publish_date=date(2023, 2, 20), price=55.50, stock=40)
]Book.objects.bulk_create(books)  # 批量插入

get_or_create

查询记录,若不存在则创建:

book, created = Book.objects.get_or_create(title="Django 入门",  # 查询条件defaults={  # 若不存在,新增时的其他字段"author": "张三","publish_date": date(2023, 1, 1),"price": 59.99,"stock": 100}
)
# created 是布尔值:True 表示新建,False 表示查询到已有记录

查询

基础查询

all

查询所有记录

all_books = Book.objects.all()

get

查询单条记录(必须匹配一条,否则报错)

book = Book.objects.get(id=1)  # 通过 ID 查询
book = Book.objects.get(title="Django 入门")  # 通过字段查询

filter

查询符合条件的多条记录

# 价格大于 50 的书
expensive_books = Book.objects.filter(price__gt=50)# 作者是张三且库存大于 0 的书
zhang_books = Book.objects.filter(author="张三", stock__gt=0)

exclude

# 排除价格小于等于 50 的书(即查询价格 >50 的书)
cheap_books = Book.objects.exclude(price__lte=50)

高级查询

条件表达式

  • __gt:大于(price__gt=50 → 价格 >50)
  • __lt:小于
  • __gte:大于等于
  • __lte:小于等于
  • __contains:包含(模糊查询,区分大小写)
  • __icontains:包含(不区分大小写)
  • __in:在列表中(author__in=[“张三”, “李四”])
  • __range:在范围内(publish_date__range=(start_date, end_date))
  • __isnull:是否为 null(author__isnull=True)
# 书名包含 "Django" 的书(不区分大小写)
django_books = Book.objects.filter(title__icontains="django")# 2023 年出版的书
from datetime import date
start = date(2023, 1, 1)
end = date(2023, 12, 31)
books_2023 = Book.objects.filter(publish_date__range=(start, end))

F查询

F() 表达式用于直接引用模型字段的值,允许在数据库层面进行字段间的比较或运算,而无需先将数据加载到 Python 内存中。

# 示例:查询库存大于销量的书籍(假设有 sales 字段)
books = Book.objects.filter(stock__gt=F('sales'))# 解释:直接在数据库中比较 stock 和 sales 字段,避免了 Python 层面的计算

字段运算

# 示例1:所有书籍涨价 10%
Book.objects.all().update(price=F('price') * 1.1)# 示例2:某本书库存减少 5
book = Book.objects.get(id=1)
book.stock = F('stock') - 5
book.save()# 注意:保存后需要刷新实例才能看到最新值(因为 F() 是数据库层面的操作)
book.refresh_from_db()  # 从数据库重新加载数据

跨关系使用

class Author(models.Model):name = models.CharField(max_length=100)age = models.IntegerField()class Book(models.Model):title = models.CharField(max_length=200)author = models.ForeignKey(Author, on_delete=models.CASCADE)publish_year = models.IntegerField()# 示例:查询出版年份大于作者年龄的书籍(假设作者年龄与出版年份有逻辑关联)
books = Book.objects.filter(publish_year__gt=F('author__age'))

Q 查询

Q() 表达式用于构建复杂的查询条件,支持逻辑运算符(与、或、非),可以组合多个查询条件。

|

# 示例:查询价格大于 100 元 或 作者是 "张三" 的书籍
books = Book.objects.filter(Q(price__gt=100) | Q(author="张三")  # | 表示逻辑或
)

&

# 示例:查询价格大于 100 元 且 作者是 "张三" 的书籍
# 等价于 filter(price__gt=100, author="张三"),但 Q() 更灵活
books = Book.objects.filter(Q(price__gt=100) & Q(author="张三")  # & 表示逻辑与
)

~

# 示例:查询作者不是 "张三" 的书籍
books = Book.objects.filter(~Q(author="张三")  # ~ 表示逻辑非
)

嵌套使用

# 示例:查询(价格 >100 且 2023 年出版) 或 (作者是张三且库存 >0)的书籍
books = Book.objects.filter(Q(price__gt=100, publish_year=2023) | Q(author="张三") & Q(stock__gt=0)
)
# 等价于 Q(author="张三") & Q(price__gt=100)
books = Book.objects.filter(author="张三", Q(price__gt=100))

F () 与 Q () 结合使用

# 示例:查询(库存 > 销量 且 价格 > 50) 或 (作者是张三)的书籍
books = Book.objects.filter((Q(stock__gt=F('sales')) & Q(price__gt=50)) | Q(author="张三")
)

排序与限制

order_by

# 按价格升序(默认)
books_by_price = Book.objects.order_by("price")# 按价格降序(加负号)
books_by_price_desc = Book.objects.order_by("-price")

first / last

first_book = Book.objects.first()
last_book = Book.objects.last()

reverse

反转 QuerySet 顺序(需先排序)

reversed_books = Book.objects.order_by("price").reverse()  # 等效于 order_by("-price")

切片

# 取前 10 条
top10_books = Book.objects.all()[:10]# 分页:取第 11-20 条
page2_books = Book.objects.all()[10:20]

分组聚合

分组聚合(Group By + Aggregation)是处理统计分析类需求的强大工具,常用于计算分组数据的总和、平均值、数量等。

from django.db.models import Avg, Sum, Count# 平均价格
avg_price = Book.objects.aggregate(Avg("price"))  # {'price__avg': 58.33}# 总库存
total_stock = Book.objects.aggregate(Sum("stock"))  # {'stock__sum': 220}# 按作者分组,统计每个作者的书籍数量
author_book_count = Book.objects.values("author").annotate(Count("id"))
# 结果:[{'author': '张三', 'id__count': 1}, {'author': '李四', 'id__count': 1}, ...]

去重计数(distinct=True)

# 统计每个作者的不同出版社数量(假设有 publisher 字段)
result = Book.objects.values('author').annotate(publisher_count=Count('publisher', distinct=True)
)

对 DateTimeField 字段,可按年、月、日等粒度分组(需结合 Trunc 函数):

from django.db.models.functions import TruncYear, TruncMonth# 按出版年份分组,统计每年出版的书籍数量
result = Book.objects.annotate(publish_year=TruncYear('publish_date')  # 提取年份
).values('publish_year').annotate(book_count=Count('id')
)# 按出版月份分组(如 2023-01, 2023-02)
result = Book.objects.annotate(publish_month=TruncMonth('publish_date')  # 提取年月
).values('publish_month').annotate(book_count=Count('id')
)

多个聚合值

# 按作者分组:统计书籍数量、平均价格、总库存
result = Book.objects.values('author').annotate(book_count=Count('id'),avg_price=Avg('price'),total_stock=Sum('stock')
)

多字段分组 + 过滤

# 按作者和出版年份分组,统计每组书籍数量
result = Book.objects.values('author', 'publish_year').annotate(book_count=Count('id')
).order_by('author', 'publish_year')  # 按分组字段排序# 结果格式:
# [
#   {'author': '张三', 'publish_year': 2023, 'book_count': 2},
#   {'author': '张三', 'publish_year': 2022, 'book_count': 1},
#   ...
# ]

子查询与聚合结合

# 子查询:统计每个作者的书籍数量
author_book_count = Book.objects.filter(author=OuterRef('pk')
).annotate(count=Count('id')
).values('count')# 主查询:查询所有作者,并附加其书籍数量
authors = Author.objects.annotate(book_count=Subquery(author_book_count[:1])  # 取子查询结果的第一条
)

分组后过滤(filter() 与 having 区别)

  • filter():在分组之前过滤数据(类似 SQL 的 WHERE)。
  • annotate() 后再 filter():在分组之后过滤(类似 SQL 的 HAVING)。
# 示例1:先过滤(2020年以后出版的书),再分组统计
result1 = Book.objects.filter(publish_year__gt=2020).values('author').annotate(book_count=Count('id')
)# 示例2:先分组,再过滤分组结果(只保留书籍数量 > 2 的作者)
result2 = Book.objects.values('author').annotate(book_count=Count('id')
).filter(book_count__gt=2)  # 此处 filter 等效于 HAVING book_count > 2

对关联模型(如外键、多对多)进行分组聚合时,需通过双下划线(__)关联字段。

class Author(models.Model):name = models.CharField(max_length=100)country = models.CharField(max_length=50)  # 作者所属国家class Book(models.Model):title = models.CharField(max_length=200)author = models.ForeignKey(Author, on_delete=models.CASCADE)  # 外键关联作者price = models.DecimalField(max_digits=10, decimal_places=2)
# 按作者的国家分组,统计每个国家的书籍总数和平均价格:
from django.db.models import Count, Avgresult = Book.objects.values('author__country').annotate(total_books=Count('id'),avg_book_price=Avg('price')
)# 结果格式:
# [
#   {'author__country': '中国', 'total_books': 10, 'avg_book_price': 55.5},
#   {'author__country': '美国', 'total_books': 8, 'avg_book_price': 62.3},
#   ...
# ]
常用聚合函数
  • Count
  • Sum
  • Avg
  • Max
  • Min
  • StdDev: 标准差(仅部分数据库支持)
  • Variance: 方差(仅部分数据库支持)

values

返回字典列表(键为字段名)。

# 获取所有书籍的标题和作者
book_data = Book.objects.values('title', 'author__name')
# 结果:[{'title': 'Django 入门', 'author__name': '张三'}, ...]

values_list

# 获取所有书籍标题(扁平列表)
titles = Book.objects.values_list('title', flat=True)
# 结果:['Django 入门', 'Python 编程', ...]

only

仅加载指定字段(其他字段访问会触发新查询)。

# 只加载书名和作者(适合列表展示等场景)
books = Book.objects.only('title', 'author__name')

defer

延迟加载指定字段(与 only 相反)。

# 不加载大文本字段 content(适合不需要展示详情的场景)
books = Book.objects.defer('content')

select_related

select_related:用于外键 / 一对一关系,通过 JOIN 一次性加载关联对象(适用于 “单对象” 关联)。

# 普通查询(会产生 N+1 条 SQL:1 条查书籍,N 条查对应作者)
books = Book.objects.all()
for book in books:print(book.author.name)  # 每次访问 author 都会触发新查询# 优化后(仅 1 条 SQL,通过 JOIN 加载书籍和关联的作者)
books = Book.objects.select_related('author').all()
for book in books:print(book.author.name)  # 无额外查询

prefetch_related

用于多对多 / 反向外键关系,通过单独查询关联对象再在 Python 中关联(适用于 “多对象” 关联)。

# 优化多对多查询(书籍与标签)
books = Book.objects.prefetch_related('tags').all()
for book in books:print([tag.name for tag in book.tags.all()])  # 无额外查询
# 加载书籍、作者及其所有作品
books = Book.objects.select_related('author').prefetch_related('author__books').all()

原始 SQL 查询

raw

raw(sql, params=None):执行原始 SQL 并返回模型实例

books = Book.objects.raw("SELECT * FROM myapp_book WHERE price > %s", [50])

extra()

附加 SQL 片段(不推荐,建议用 annotate 或 F/Q)

books = Book.objects.extra(where=["price > 50"])

QuerySet 基本特性

QuerySet 是 Django ORM 中用于与数据库交互的核心对象,它代表数据库中一组记录的集合,支持链式操作和延迟执行。

延迟执行(Lazy Evaluation)

QuerySet 不会立即执行数据库查询,直到真正需要使用数据时才会触发 SQL 执行。这是 QuerySet 最核心的特性之一。

# 定义 QuerySet(未执行查询)
books = Book.objects.filter(author="张三")# 以下操作会触发 SQL 执行:
print(books)  # 打印时
for book in books:  # 迭代时pass
list(books)  # 转换为列表时
if books:  # 判断布尔值时

可链式调用

# 链式调用:价格大于 50 且 2023 年出版的书,按价格降序
books = Book.objects.filter(price__gt=50).filter(publish_year=2023).order_by("-price")

不可变对象

QuerySet 是不可变的,每次链式调用都会返回一个新的 QuerySet,原 QuerySet 不会被修改:

qs1 = Book.objects.filter(author="张三")
qs2 = qs1.filter(price__gt=50)  # qs1 不变,qs2 是新的 QuerySet
复制 QuerySet

由于 QuerySet 是不可变的,可通过 all() 复制:

qs1 = Book.objects.filter(author="张三")
qs2 = qs1.all()  # 复制 qs1,后续操作不影响 qs1

QuerySet 与其他对象的区别

在这里插入图片描述

更新数据

save

单个实例更新

# 1. 查询实例
book = Book.objects.get(id=1)# 2. 修改字段
book.price = 65.99  # 涨价
book.stock -= 1  # 库存减1# 3. 保存到数据库
book.save()  # 执行 UPDATE 语句

update

# 所有张三的书涨价 10%
Book.objects.filter(author="张三").update(price=F("price") * 1.1)
# 注意:F() 用于引用字段本身,避免先查询再计算的竞态问题

bulk_update

# 1. 查询需要更新的实例
books = Book.objects.filter(author="张三")# 2. 修改实例字段
for book in books:book.stock += 5  # 库存各加5# 3. 批量更新(指定需要更新的字段)
Book.objects.bulk_update(books, ["stock"])

条件更新与 Case/When

from django.db.models import Case, When, IntegerField# 对不同书籍设置不同库存
Book.objects.update(stock=Case(When(title__icontains="Django", then=100),  # Django 相关书籍库存设为 100When(author="张三", then=50),  # 张三的书库存设为 50default=0,  # 其他默认 0output_field=IntegerField())
)

删除

book = Book.objects.get(id=1)
book.delete()  # 执行 DELETE 语句# 删除所有库存为 0 的书
Book.objects.filter(stock=0).delete()
  • 删除操作不可逆,谨慎使用。
  • 若模型设置了 on_delete 关联关系(如外键),删除时会触发对应的级联行为(如 CASCADE 级联删除)。

其他操作

iterator

适合大数据量,减少内存占用(一次加载一批)

# 处理 100 万条记录,每次加载 1000 条
for book in Book.objects.iterator(chunk_size=1000):process(book)

refresh_from_db

刷新实例(从数据库重新加载)

book = Book.objects.get(id=1)
# 其他操作可能修改了数据库中的记录...
book.refresh_from_db()  # 从数据库重新加载最新数据

count

# 总书籍数量
total = Book.objects.count()# 张三的书籍数量
zhang_count = Book.objects.filter(author="张三").count()

exists

# 判断是否有价格大于 100 的书
has_expensive = Book.objects.filter(price__gt=100).exists()  # 返回布尔值
http://www.dtcms.com/a/306413.html

相关文章:

  • 疯狂星期四文案网第24天运营日记
  • cmake项目基本demo
  • AWS IAM:安全访问管理的核心指南
  • 开发避坑短篇(10):ArithmeticException无限循环小数的精确处理方案
  • 地图可视化实践录:显示高德地图和百度地图
  • JavaWeb前瞻—JDBC
  • Rabbitmq中常见7种模式介绍
  • QString 内存机制详解
  • 【Excel】制作双重饼图
  • 恢复IP地址
  • 明远智睿V2H核心模组:工业4.0时代的“性价比革命”
  • 双塔模型 + 自监督学习:解决长尾物品表征难题
  • IBus vs. Fcitx5:一场 Linux 输入法框架的正面交锋
  • Maximum Subarray Sum
  • Redis高可用性
  • CSM7020L 磷酸铁锂电池充电管理的太阳能草坪灯 LED 驱动芯片 SOT23-6封装 带多种反接功能
  • LLM之RAG理论(十八)| ChatGPT DeepResearch 深度研究功能全面技术分析报告
  • 使用Docker 在Rocky Linux 9.5上在线安装Dify
  • 2025年DDoS攻防战:六层防护体系构建业务“数字免疫”
  • 从0开始学linux韦东山教程Linux驱动入门实验班(7)
  • 伦敦招聘数据管道系统设计与实现
  • android-PMS-常见定制场景
  • 【文章浏览 I】
  • 【7】串口编程三种模式(查询/中断/DMA)韦东山老师学习笔记(课程听不懂的话试着来看看我的学习笔记吧)
  • luoguP13511 [KOI P13511 [KOI 2025 #1] 等腰直角三角形
  • S3、SFTP、FTP、FTPS 协议的概念、对比与应用场景
  • vulhub ica1靶场攻略
  • AI框架工具FastRTC快速上手2——整体框架及Stream类详解
  • 浏览器pdf、image显示
  • MaxKB+MinerU:通过API实现PDF文档解析并存储至知识库