Django-ORM基本增删查改
建议阅读顺序: 增加-查询-更新-删除
建议看右边的文章目录,根据需求看!!!
项目基本结构及字段
数据表:
- BookInfo表(书籍信息表)
- RoleInfo表(人物信息表)
Models.py中表的定义
from django.db import models
# Create your models here.
class Book(models.Model):
class Meta:
db_table = 'BookInfo'
verbose_name = '图书信息'
name = models.CharField(max_length=128, blank=False, verbose_name='书名')
pub_time = models.DateField(verbose_name='发布时间')
author = models.CharField(max_length=128, blank=False, default='未知', verbose_name='作者名')
sale = models.IntegerField(blank=False, default=0, null=False)
comment_num = models.IntegerField(blank=False, default=0, null=False)
class Role(models.Model):
class Meta:
db_table = 'RoleInfo'
verbose_name = '角色信息'
name = models.CharField(max_length=128, blank=False, verbose_name='角色名')
book = models.ForeignKey('Book', on_delete=models.CASCADE, verbose_name='所属书籍') # 外键约束
is_good = models.BooleanField(blank=False, verbose_name='是否为好角色')
BookInfo表基本数据
RoleInfo表基本数据
必看: Django Shell的使用
Django Shell 是集成于项目的命令提示行,便于我们对ORM进行数据测试
# 使用方法
cd 项目根目录(manage.py所在目录)
python ./manage.py shell
长得其实就是Python命令提示行
进入Django Shell后,我们可以先导入我们定义好的Model类,进行相关的调试
from Book.models import *
# 测试查询
Book.objects.get(id__exact=21)
# 返回结果
# 这样我们不用进行视图的编写,就可以调试ORM
1. 增加数据
1.1 使用objects.create 新增数据
objects是models子类的属性
from Book.models import * # 引用Models中的所有ORM表结构
增加数据
Book.objects.create(
name='create新增数据',
pub_time='2001-11-25',
author='Ruan',
)
# 该方法直接调用models对象增加数据,直接加入到数据库.
1.2 使用实例化对象.save() 保存数据
x = Book(
name="我的简史",
pub_time="2012-04-25",
author="霍金",
)
type(x) -> Book.models.Book 即Book类的实例对象
x.save() #必须调用.save()才会写入数据库
2. 更新数据 (建议先看查询数据)
更新数据=SQL中的UPDATE,Django进行了封装,用法简单
更新数据需要使用models对象的update()进行更新
2.1 update更新
#### 语法规则:
QuerySet|obj.filter(条件).update('字段1'=新值,"字段2"=新值)
#### 需求:
#### 将所有author = 霍金的行的 author字段
objs = Book.objects.filter(author='霍金') # 所有=霍金的对象
-> QuerySet
objs.update(
author='史蒂夫 · 霍金'
) # 更新所有数据
Tips:
update必须是一个QuerySet,也就是说obj.get的数据是不能update的
2.2 修改后save
通过对model对象的值进行修改,再通过save保存,也是常见的更新数据方式
obj = Book.objects.get(id=26) #根据id查询只有一个,直接get即可
obj.author='狗狗'
obj.save()
3. 删除操作 (建议先看查询数据)
删除操作是SQL中的DELETE的封装,很简单,[QuerySet|obj].delete()
简单来讲,就是先查询,再删除
3.1 单个数据删除 obj.delete()
#### 删除id=25的书籍
Book.objects.filter(id=25).delete()
3.2 多条数据删除 QuerySet.delete()
#### 删除评论>3000的所有书籍
Book.objects.filter(comment_num__gt=3000).delete()
4. 查询数据
基本查询函数共计有三种
# filter: 返回所有符合条件的
# get: 只能返回1个,如果查出来多个,直接报错
# exclute: 返回除了查找的以外的所有的,相当于not
4.1 get查询函数
get方法只能返回一个,返回多个就会报错
Book.objects.get(id__exact=21) # 返回一个Book对象
# xx_exact:严格模式 等同于 xx
# 也就是说.get(id__exact=21) 和 .get(id=21) 是一样的
4.2 filter查询函数
filter返回满足条件的所有Book对象,返回QuerySet[Book_obj]
-> Book.objects.get(id__exact=21)
-> <Book: Book object (21)> # 返回的是一个Book对象
-> Book.objects.filter(id__exact=21)
-> <QuerySet [<Book: Book object (21)>]> # 返回的是QuerySet
4.3 exclute 返回除了给出条件以外的所有值
例如:获取除了ID=2以外的所有Book对象
Book.objects.exclute(id=2) # 除了id=2的,全部都返回,返回QuerySet,其他参数与filter一样
4.4 获取数据个数
# 语法格式:
QuerySet.count()
obj.查询语句(条件).count()
Book.objects.exclude(id=22).count() # 返回id不为22的书籍的数量
5. 复杂单条件查询(不包含外键查询)
Django中所有的复杂条件查询都是以传入参数 字段名__函数的方法进行查询
5.1 值大小比较条件查询(日期/数字类型通用)
# 查询发布时间在2000年以后的所有图书
Book.objects.filter(pub_time__gt='2000-01-01')
# __gt : 大于某个值
# __gte: 大于等于某个值的所有值
# __lt : 小于某个值
# __lte: 小于等于某个值的所有值
# -> 如果返回不是一个,则会报错: Book.models.Book.MultipleObjectsReturned
# -> 所有日期相关的类型,都必须是 YYYY-MM-DD格式
Book.objects.filter(pub_time__year='2022') # 查询书籍发布时间在2022年的数据的所有书籍
# __year : 日期类型年=XX的,传字符串或者数字都可以
Book.objects.filter(pub_time__month='7') # 查询发布时间在7月的所有书籍
# __month : 月类型,同上
5.2 值含于(in)条件查询
# 查询作者名称是 "霍金" 或者 "雷欧幻象" 的所有书籍
# in条件不支持字符串查询,字符串有另外的方法
Book.objects.filter(author__in=["霍金", "雷欧幻象"])
# __in : 包含于[xx,xx]种的值,传QuerySet类型值
5.3 正则表达式条件查询
# 查询作者满足正则表达式 ^霍.* 的值 -> 霍开头
Book.objects.filter(author__regex=r'^霍.*')
# __regex : 满足正则表达式的值
5.4 字符串包含条件查询(LIKE)
# 查询作者名包含 "霍" 的所有书籍,类似于SQL中的 %霍%
Book.objects.filter(author__contains='霍')
# __contains : 包含"xx"字符串的值
5.5 字符串结尾/开头条件查询
# 查询作者以 "金"结尾的书籍
Book.objects.filter(author__endswith='金')
# __endswith : 以"xx"字符串结尾的值
# 查询作者以 "雷"开头的书籍
Book.objects.filter(author__startswith='雷')
# __startswith : 以"xx"字符串结尾的值
5.6 判断空值条件查询
# 返回所有作者不为空的书籍对象
Book.objects.filter(author__isnull=False)
# __isnull : 值是否为空的,传Bool类型
6. 复杂多条件 和/或 查询(Q对象)
6.1 多条件查询的几种方法
6.1.1 使用filter或者多参数
需求: 查询作者名包含霍金 并且 评论数 > 4000 的书籍
#### 多条件查询有多种方法
### 1. 多次使用filter
Book.objects.filter(author__contains='霍金').filter(comment_num__gt=4000)
### 2. 一个filter中传入多个参数
Book.objects.filter(author__contains='霍金', comment_num__gt=4000)
6.1.2 使用Q对象,实现 and 以及 or 查询
Q语法格式:
filter(Q(条件1) “|/&” Q(条件2) …更多条件)
# Q对象需要导入
from django.db.models import Q
# 格式:
# filter(Q(条件1) "|/&" Q(条件2) ...更多条件)
# Q对象的and以及or,需要使用 & | 运算符
# 查询作者名包含霍金 并且 评论数 > 4000 的书籍
Book.objects.filter(Q(author__contains='霍金') & Q(comment_num__gt=4000))
# 也许这个需求,看不出Q的方便性
# 现在需求改为,查询author中包含'霍金' 或者 评论数>4000的书籍
# 这时Q对象就可以实现
# 查询 作者名包含霍金 或者 评论数 > 4000 的书籍
Book.objects.filter(Q(author__contains='霍金') | Q(comment_num__gt=4000))
7. 不同字段之间的对比查询(F对象)
现在需求是,需要对比评论比销量高的数据,你该怎么办??
这里引入F对象
# F对象需要导入
from django.db.models import F
# 语法格式
# filter(条件=F(字段名称))
# 评论比购买数大的书籍
Book.objects.filter(comment_num__gt=F('sale'))
# 需求:
# 查询评论比销量大2倍的书籍或者销量大于10000的书籍
Book.objects.filter(Q(comment_num__gt=F('sale') * 2) | Q(sale__gt=100000))
8. 聚合查询函数
8.1 聚合函数的介绍和简单使用
众所周知,在SQL中,有对应的SUM(求和),AVG(均值)等函数,而Django也帮忙封装了相关的函数
函数的使用,需要在aggregate方法中传入函数
聚合函数,需要单独导入
from django.db.models import Sum, Avg # 导入求和,均值函数
# 语法格式
[model.objects|QuerySet].aggregate(函数1(字段),函数2(字段)...)
# -> dict 返回字典 {"字段_函数小写":结果,}
实现查询书籍的总销量和平均销量
Book.objects.aggregate(Sum('sale'),Avg('sale'))
-> {'sale__sum': 348123, 'sale__avg': 43515.375}
8.2 聚合函数与查询函数的连用
#### 需求:
#### 查询数字作者名字中带 "霍金" 或者 书发布时间在2010年以后的 的书籍的平均销量以及平均评论
Book.objects.filter(Q(author__contains='霍金') | Q(pub_time__gt="2010-01-01")).aggregate(Avg('sale'),Avg('comment_num'))
# 使用Q对象,进行 "或" 查询,在返回的QuerySet中执行aggregate
9. 排序函数的使用 ORDER BY
排序函数就是Django封装的,SQL中的ORDER BY
# 语法格式:
# obj.order_by(字段名) 默认升序排序
# obj.order_by(-字段名) # 字段名前加减号代表降序排序
#### 需求:
#### 返回升序排序评论数量数据
#### 返回降序排序销售数量数据
Book.objects.order_by('comment_num') # 直接order_by 升序排序
Book.objects.order_by('-comment_num') # "-字段名" 逆序排序
10. 表关联查询 JOIN 及关联筛选
SQL中的JOIN查询,可以让我们查询外键约束的相关数据,Django也进行了相关封装
先搞清楚我们两个数据库之间的关系
-
Class Book (书籍信息表对象)
-
Class Role (角色信息表对象)
其中Role的 “book” 字段,关联Book的 "id"字段
# 代码实现如下
book = models.ForeignKey('Book', on_delete=models.CASCADE, verbose_name='所属书籍') # 外键约束,约束于 'Book'类
10.1 用从表查主表 一对多关系
(“角色信息” 查 “书籍信息”) 一对多关系
10.1.1 从表查主表的值
# 从表查主表语法格式:
# "从表对象.get(条件).关联字段" -> 返回 主表对象
#### 需求:
#### 现在要查询 角色"张飞"对应的书籍的销量
book_obj = Role.objects.get(name='张飞').book
-> 返回一个Book对象,可以调用其其他信息
book_obj.sale
-> 返回 "三国演义" 的销量
# 连起来
Role.objects.get(name='张飞').book.sale # 直接查询张飞对应书籍的销量
10.1.2 通过主表的值筛选从表的值 (不太好理解,多看看写的案例就懂了)
可能有些绕口,上面10.1.1的案例是通过"张飞"这个名字获得他对应的书籍的"销量"
现在需求变了,需要直接查询书籍销量大于1000的书籍里面的角色有哪些
# 语法格式:
# 从表对象.filter(从表与主表的关联字段__查询条件)
-> QuerySet
#### 需求:
#### 查询书籍销量大于1000的书籍里面的角色
从表对象:Role.objects
关联字段:book
查询条件:sale__gt=1000
# 连起来就是
Role.objects.filter(book__sale__gt=1000)
-> QuerySet
10.2 主表查从表 多对一关系
(“书籍信息” 查 “角色信息”) 多对一关系
10.2.1 主表查从表的值
如果遇到这样的需求:查询三国演义这本书(主表)中所有的角色信息(从表)
# 语法格式:
# Django为主表封装了一个属性
# 属性命名格式: 从表(小写)_set
# 所以调用格式: 主表对象.从表(小写)_set -> QuerySet
#### 需求:
#### 查询三国演义这本书(主表)中所有的角色信息(从表)
book = Book.objects.get(name='三国演义') # 先查询三国演义这本书
book.role_set.all()
-> QuerySet
#### 需求2:
#### 查询三国演义这本书中 所有名字包含"飞"的角色:
Book.objects.get(name='三国演义').role_set.all().filter(name_contains='飞')
-> QuerySet
10.2 主表查从表 多对一关系
(“书籍信息” 查 “角色信息”) 多对一关系
10.2.1 主表查从表的值
如果遇到这样的需求:查询三国演义这本书(主表)中所有的角色信息(从表)
# 语法格式:
# Django为主表封装了一个属性
# 属性命名格式: 从表(小写)_set
# 所以调用格式: 主表对象.从表(小写)_set -> QuerySet
#### 需求:
#### 查询三国演义这本书(主表)中所有的角色信息(从表)
book = Book.objects.get(name='三国演义') # 先查询三国演义这本书
book.role_set.all()
-> QuerySet
#### 需求2:
#### 查询三国演义这本书中 所有名字包含"飞"的角色:
Book.objects.get(name='三国演义').role_set.all().filter(name_contains='飞')
-> QuerySet