前言
系列文章目录
[Python]目录
文章目录
- 前言
- 🍉 ORM
- 🍉 shell
- 🍉 模型类与数据的准备
- 🍒 模型类
- 🍒 数据
- 🍉 查询数据
- 🍒 查询集
- 🍓 查询集的特性
- 🍎 惰性执行
- 🍎 缓存
- 🍒 简单查询
- 🍓 all():查询模型对应数据表中所有数据
- 🍓 get():查询数据表中满足指定条件的数据
- 🍓 values():获取需要的字段
- 🍓 distinct():对查询出来的数据记录进行去重
- 🍓 count():统计查询结果中数据记录的数量
- 🍒 过滤查询 filter() & get() & exclude()
- 🍓 语法
- 🍓 运算符
- 🍓 相等
- 🍓 模糊查询
- 🍓 空查询
- 🍓 范围查询
- 🍓 比较查询
- 🍓 日期查询
- 🍒 F对象(两个属性进行比较)
- 🍓 语法
- 🍒 Q对象(逻辑或与非查询)
- 🍓 语法
- 🍓 逻辑与查询
- 🍓 逻辑或查询
- 🍓 逻辑非查询
- 🍒 聚合函数
- 🍒 排序
- 🍒 关联查询
- 🍓 由一到多的访问
- 🍓 由多到一的访问
- 🍓 由一到一的访问
- 🍓 由多到多的访问
- 🍓 select_related()
- 🍓 prefetch_related()
- 🍓 关联查询的筛选
- 🍉 新增数据
- 🍒 方式一:实例化模型类,save()保存新增数据
- 🍒 方式二:直接create()新增数据入库
- 🍉 更新数据
- 🍒 方法一:获取模型对象修改对象属性,save()保存修改数据
- 🍒 方法二:直接update()修改数据
- 🍒 objects调用update()批量更新所有数据
- 🍒 批量更新多行数据
- 🍉 删除数据
- 🍒 方法一:获取指定数据对象调用delete()删除该数据对象
- 🍒 方法二:过滤出指定数据对象调用delete()删除过滤出来的数据对象
- 🍒 删除多行数据
- 🍒 删除全部数据
- 🍉 执行原生SQL
- 🍒 raw()
- 🍒 游标
- 🍓 用法
- 🍓 插入数据
- 🍓 查询数据
- 🍓 更新数据
- 🍓 删除数据
- 🍉 事务处理
- 🍒 装饰器方式
- 🍒 with 语句方式
🍉 ORM
在Django MVT设计模式中的Model,专门负责和数据库进行交互,对应的文件 models.py。Model中内嵌了ORM框架,使得我们不需要直接面向数据库编程,而是定义模型类,通过模型类和对象完成数据库表的增删改查。
ORM框架就是把数据库表中的行与相应模型类的对象相对应,把数据库中的表与模型类相对应,把数据库中表的字段与模型类的属性相对应。
使用ORM框架操作数据库,我们可以不用关心底层具体使用的是哪个数据库,只需要关心ORM框架即可。如果需要使用不同的数据库,我们只需要在Django框架中进行相应的配置,ORM会自动连接对应的数据库,如果需要对数据库进行增删改查,我们也只需要操作ORM即可,ORM会自动生成对应的数据库的sql语言。
🍉 shell
Django的manage工具提供了shell命令,以便我们可以直接在终端中执行测试python语句。
Django manage提供的shell类似于ipython;
使用shell工具,可以帮助我们更好的测试代码,对于有关模型的代码(数据对象的增删改查)可以使用shell进行测试,就不用书写路由和请求响应到浏览器客户端进行查看。
启动shell,在命令窗口运行:
python manage.py shell
测试,导入两个模型类,并查询两个模型类对应的所有数据对象:
# 导入两个模型类
from book.models import BookInfo,PeopleInfo
# 查询两个模型类对应的所有数据对象
BookInfo.objects.all()
PeopleInfo.objects.all()
有关模型类的代码写在models.py中,对数据进行增删改查的代码书写在views.py中,对数据进行增删改查需要实例化模型类,在views.py中导入模型类,对数据进行增删改查。
🍉 模型类与数据的准备
🍒 模型类
from django.db import models
# Create your models here.
class BookInfo(models.Model):
name = models.CharField(max_length=10, unique=True, verbose_name='书籍名')
pub_date = models.DateField(null=True) # 发布日期
read_count = models.IntegerField(default=0) # 阅读数
comment_count = models.IntegerField(default=0) # 评论数
is_delete = models.BooleanField(default=False) # 是否被逻辑删除
class Meta:
db_table = 'bookinfo' # 指定模型对应数据库中表的表名
verbose_name = '书籍信息' # 修改后台admin显示的表名
def __str__(self):
return self.name
# 准备人物列表信息的模型类
class PeopleInfo(models.Model):
# 性别的可选值 0对应male 1对应female
GENDER_CHOICES = (
(0, 'male'),
(1, 'female')
)
name = models.CharField(max_length=20, verbose_name='名称') # 人物的名字
gender = models.SmallIntegerField(choices=GENDER_CHOICES, default=0, verbose_name='性别') # 人物的性别
description = models.CharField(max_length=200, null=True, verbose_name='描述信息') # 人物的描述信息
book = models.ForeignKey(BookInfo, on_delete=models.CASCADE, verbose_name='图书') # 引用外键,引用的模型为BookInfo
is_delete = models.BooleanField(default=False, verbose_name='逻辑删除') # 是否被逻辑删除
class Meta:
db_table = 'peopleinfo'
verbose_name = '人物信息'
def __str__(self):
return self.name
🍒 数据
表 bookinfo:
insert into bookinfo(name, pub_date, read_count,comment_count, is_delete) values
('射雕英雄传', '1980-5-1', 12, 34, 0),
('天龙八部', '1986-7-24', 36, 40, 0),
('笑傲江湖', '1995-12-24', 20, 80, 0),
('雪山飞狐', '1987-11-11', 58, 24, 0);
表 peopleinfo:
insert into peopleinfo(name, gender, book_id, description, is_delete) values
('郭靖', 1, 1, '降龙十八掌', 0),
('黄蓉', 0, 1, '打狗棍法', 0),
('黄药师', 1, 1, '弹指神通', 0),
('欧阳锋', 1, 1, '蛤蟆功', 0),
('梅超风', 0, 1, '九阴白骨爪', 0),
('乔峰', 1, 2, '降龙十八掌', 0),
('段誉', 1, 2, '六脉神剑', 0),
('虚竹', 1, 2, '天山六阳掌', 0),
('王语嫣', 0, 2, '神仙姐姐', 0),
('令狐冲', 1, 3, '独孤九剑', 0),
('任盈盈', 0, 3, '弹琴', 0),
('岳不群', 1, 3, '华山剑法', 0),
('东方不败', 0, 3, '葵花宝典', 0),
('胡斐', 1, 4, '胡家刀法', 0),
('苗若兰', 0, 4, '黄衣', 0),
('程灵素', 0, 4, '医术', 0),
('袁紫衣', 0, 4, '六合拳', 0);
🍉 查询数据
🍒 查询集
查询集,也称查询结果集(QuerySet),表示从数据库中获取的对象集合,查询集不是简单的列表。
当调用如下方法时,Django会返回查询集:
1.all()
2.filter()
3.exclude()
4.values()
5.distinct()
🍓 查询集的特性
🍎 惰性执行
创建的查询集不会立即访问数据库将数据查询出来,直到调用查询数据的时候,才会访问数据库将数据库中满足条件的数据查询出来。
🍎 缓存
如果多次数据查询使用的是同一个查询集,则只有第一次使用时会发生数据库的查询,然后Django会把结果缓存下来,再次使用这个查询集时会使用缓存的数据,减少了数据库的查询次数。如果多个查询集无法重用缓存,则每次查询都会与数据库进行一次交互,增加了数据库的负载。经过存储后,可以重用查询集,第一次查询后的查询可以直接使用缓存中的数据,减少了数据库的查询次数。
🍒 简单查询
对数据进行增删改查都可以通过调用模型类的模型管理类对象objects来实现
🍓 all():查询模型对应数据表中所有数据
all()方法可以一次性查询出模型对应的数据表中所有的数据,且该方法返回的结果为QuerySet对象。
all()方法返回的QuerySet对象是一个由数据表中所有数据记录组成的列表。
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.通过objects调用all()方法获取BookInfo模型对应数据表中的所有数据
books = BookInfo.objects.all()
🍓 get():查询数据表中满足指定条件的数据
注意,get()方法只能用于查询查询结果唯一的情况,get()方法只能用于查询返回符合要求只有一条数据的情况,当查询结果中没有记录或者记录超过一条时都会报错抛出异常。
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.通过objects调用get()方法获取BookInfo模型对应数据表中符合条件的数据记录
book = BookInfo.objects.get(id=8)
>>> from subapp01.models import BookInfo
>>> book = BookInfo.objects.get(id=8)
>>> book
<BookInfo: 射雕英雄传>
>>> book.name
'射雕英雄传'
>>> book.read_count
12
>>>
🍓 values():获取需要的字段
values()方法可以用于获取需要的字段,该方法返回的为一个QuerySet对象,该对象包含的数据类型为由指定的字段和值形成的字典。
values()方法返回的QuerySet对象是一个由数据记录字段和值组成的字典形成的列表。
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.调用values()方法获取BookInfo模型对应数据表中数据记录的指定字段
# 查询出所有数据记录后筛选出数据记录的id、name、read_count字段
books = BookInfo.objects.all().values('id', 'name', 'read_count')
>>> from subapp01.models import BookInfo # 导入模型
>>> books = BookInfo.objects.all().values('id', 'name', 'read_count')
>>> books
<QuerySet [{'id': 8, 'name': '射雕英雄传', 'read_count': 12}, {'id': 9, 'name': '天龙八部', 'read_count': 36}, {'id': 10, 'name': '笑傲江湖', 'read_count': 20}, {'id': 11, 'name': '雪山飞狐', 'read_count': 58}]>
>>> books[0]
{'id': 8, 'name': '射雕英雄传', 'read_count': 12}
>>> books[0]['name']
'射雕英雄传'
>>>
🍓 distinct():对查询出来的数据记录进行去重
该方法用于去除重复数据,返回的为一个QuerySet对象,该对象中包含的数据为去重之后的数据。
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.调用distinct()方法对查询出来的数据记录进行去重
data = BookInfo.objects.all().values('is_delete').distinct()
>>> from subapp01.models import BookInfo # 导入模型
>>> data = BookInfo.objects.all().values('is_delete').distinct()
>>> data
<QuerySet [{'is_delete': False}]>
>>>
🍓 count():统计查询结果中数据记录的数量
该方法返回查询结果中数据记录的数量。
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.调用count()方法对查询出来的数据记录进行数量的统计
count = BookInfo.objects.all().count()
>>> from subapp01.models import BookInfo
>>> count = BookInfo.objects.all().count()
>>> count
4
>>>
🍒 过滤查询 filter() & get() & exclude()
使用filter()、get()、exclude()进行过滤查询相当于SQL中的where语句
select * from 表 where 条件语句
filter():筛选符合条件的n个结果(n的取值为0-n)。返回结果为一个QuerySet对象,该对象是一个由数据记录组成的列表。
get():筛选符合条件的1个结果(返回结果只能一个,大于一个会报错),返回一个数据记录对象
exclude():排除掉符合条件之后剩下的数据组成的结果集,该结果集是一个QuerySet对象,该对象是一个由数据记录组成的列表,相当于条件语句中not。
🍓 语法
以filter()为例
filter(字段名__运算符=值)
字段名和运算符间使用两个下划线进行分割,所以属性名不能包括多个下划线。
🍓 运算符
- 相等
- exact:表示判等。
- 模糊查询
- contains:是否包含。
- 说明:如果要包含%无需转义,直接写即可。
- startswith、endswith:以指定值开头或结尾。
- 以上运算符都区分大小写,在这些运算符前加上
i
表示不区分大小写,如iexact、icontains、istartswith、iendswith.
- contains:是否包含。
- 空查询
- isnull:是否为null。
- 范围查询
- in:是否包含在范围内。
- 比较查询
- gt大于 (greater then)
- gte大于等于 (greater then equal)
- lt小于 (less then)
- lte小于等于 (less then equal)
- 不等于的运算符,使用exclude()过滤器。
- 日期查询
- year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。
🍓 相等
exact:表示判等。
# 查询编号为1的图书
# exact相当于 等于号
book = BookInfo.objects.get(id__exact=1)
# 简写形式
book = BookInfo.objects.get(id=1)
# exact相当于 等于号
book = BookInfo.objects.filter(id__exact=1)
# 简写形式
book = BookInfo.objects.filter(id=1)
返回结果为一个QuerySet对象,该对象是一个由数据记录组成的列表。
🍓 模糊查询
- contains:是否包含。
- 说明:如果要查询数据中是否包含%,无需转义,直接写%即可。
- startswith、endswith:以指定值开头或结尾。
- 以上运算符都区分大小写,在这些运算符前加上i表示不区分大小写,如iexact、icontains、istartswith、iendswith.
# 查询书名包含'湖'的图书
# 不知道返回结果有几个,使用filter
# 包含 运算符 contains
# 如果要包含%无需转义,直接写即可
books = BookInfo.objects.filter(name__contains='湖')
# 查询书名以'部'结尾的图书
# 不知道返回结果有几个,使用filter
# startswith、endswith:以指定值开头或结尾。
books = BookInfo.objects.filter(name__endswith='部')
🍓 空查询
isnull:是否为null。
# 查询书名为空的图书
books = BookInfo.objects.filter(name__isnull=True)
🍓 范围查询
in:是否包含在范围内。
# 查询编号为1或3或5的图书
books = BookInfo.objects.filter(id__in=[1, 3, 5])
🍓 比较查询
- gt大于 (greater then)
- gte大于等于 (greater then equal)
- lt小于 (less then)
- lte小于等于 (less then equal)
- 不等于的运算符,使用exclude()过滤器。
# 查询编号大于3的图书
books = BookInfo.objects.filter(id__gt=3)
# 查询编号不大于3的图书
books = BookInfo.objects.exclude(id__gt=3)
🍓 日期查询
year、month、day、week_day、hour、minute、second:对日期时间类型的属性进行运算。
# 查询1980年发表的图书
books = BookInfo.objects.filter(pub_date__year='1980')
# 查询1990年1月1日后发表的图书
books = BookInfo.objects.filter(pub_date__gt='1990-1-1')
注意:
日期的格式只能YYYY-MM-DD
🍒 F对象(两个属性进行比较)
之前的查询都是对象的属性与常量值比较,如果需要两个属性之间进行比较,则使用F对象,F对象被定义在django.db.models
中。
🍓 语法
以filter为例
filter(字段名__运算符=F('字段名'))
from django.db.models import F
# 查询阅读量大于等于评论量的图书。
books = BookInfo.objects.filter(read_count__gt=F('comment_count'))
# 查询阅读量大于2倍评论量的图书。
books = BookInfo.objects.filter(read_count__gt=F('comment_count') * 2)
🍒 Q对象(逻辑或与非查询)
如果需要实现逻辑或or、逻辑与and、逻辑非not的查询,则可以使用Q()对象结合|
、&
、~
运算符进行数据的查询,Q对象被义在django.db.models
中。
🍓 语法
# 以逻辑或查询为例
Q(属性名__运算符=值)|Q(属性名__运算符=值)|Q(属性名__运算符=值)|···
🍓 逻辑与查询
Q对象可以使用&
连接,&
表示逻辑与。
from django.db.models import Q
# 查询阅读量大于20,并且编号小于3的图书。
# 方法一: 进行多次过滤得到结果
books = BookInfo.objects.filter(read_count__gt=20).filter(id__lt=3)
# 方法二:
books = BookInfo.objects.filter(read_count__gt=20, id__lt=3)
# 方法三:使用Q对象相与
books = BookInfo.objects.filter(Q(read_count__gt=20) & Q(id__lt=3))
🍓 逻辑或查询
逻辑或查询只能使用Q对象实现
Q对象可以使用|
连接,|
表示逻辑或。
# 查询阅读量大于20,或编号小于3的图书
books = BookInfo.objects.filter(Q(read_count__gt=20) | Q(id__lt=3))
🍓 逻辑非查询
Q对象前可以使用~
操作符,表示逻辑非 not。
# 查询编号不等于3的图书。
books = BookInfo.objects.exclude(id=3)
books = BookInfo.objects.filter(~Q(id=3))
🍒 聚合函数
在查询数据时需要使用聚合函数,则需要使用aggregate()
过滤器调用聚合函数来进行数据的查询。
聚合函数包括:Avg平均,Count数量,Max最大,Min最小,Sum求和,被定义在django.db.models
中。
语法:
aggregate(聚合函数('字段名'))
注意aggregate的返回值是一个字典类型,格式如下:
{'属性名__聚合类小写':值}
# 导入聚合函数
from django.db.models import Avg, Count, Max, Min, Sum
# 查询图书的总阅读量。
books = BookInfo.objects.aggregate(Sum('read_count'))
🍒 排序
使用order_by()
对结果进行排序.
降序排序只需要在指定字段前加一个负号即可
# 根据评论数对所有图书的查询结果进行排序
# 默认升序
books = BookInfo.objects.all().order_by('comment_count')
# 降序
books = BookInfo.objects.all().order_by('-comment_count')
# 根据阅读数和id对所有图书的查询结果进行排序
# 阅读数升序,相同时按照id号升序排序
books = BookInfo.objects.all().order_by('read_count', 'id')
# 阅读数升序,相同时按照id号降序排序
books = BookInfo.objects.all().order_by('read_count', '-id')
🍒 关联查询
🍓 由一到多的访问
已知主表(被从表建立外键引用)数据,关联查询从表(引用主表)数据。
语法:
当在两个模型中使用外键建立关联之后,Django会在被从表关联的主表模型中自动生成添加可以用于进行反向操作(因为外键在从表,主表连接从表查询数据为反向操作)的属性
从表模型类名小写
,如果在从表定义外键时有指定反向操作时使用的名称,则使用指定的名称进行反向操作。
主表模型(或实例对象).从表模型类名小写_set
# 查询书籍为1的所有人物信息
# 1. 查询id为1的书籍
book = BookInfo.objects.get(id=1)
# 2. 根据书籍关联任务信息
people = book.peopleinfo_set.all()
🍓 由多到一的访问
已知从表数据,关联查询主表数据。
语法:
从表模型(或实例对象).从表模型中的外键属性
from book.models import PeopleInfo
# 查询人物为1的书籍信息
# 1. 查询id为1的人物信息
person = PeopleInfo.objects.get(id=1)
# 2. 根据人物信息获取人物对应的书籍信息
book = person.book
🍓 由一到一的访问
一到一的访问为上述一到多和多到一的特例,在进行主表关联从表和从表关联主表的查询时,依旧可以使用上述的方法进行数据的关联查询。有定义外键的模型使用外键进行关联,没有定义外键的模型(被关联的模型)使用Django在被关联的模型中自动生成添加用于进行反向操作的属性 关联模型类名小写
进行关联查询。
🍓 由多到多的访问
与上述一到多和多到一的查询方法类似,有定义外键的模型使用外键进行关联,没有定义外键的模型(被关联的模型)使用Django在被关联的模型中自动生成添加用于进行反向操作的属性 关联模型类名小写
进行关联查询。
🍓 select_related()
可以将关联的模型数据提取出来,可以减少数据库查询的次数。
用于一到多的关联查询
主表模型.objects.select_related("关联从表模型名小写")
🍓 prefetch_related()
可以将关联的模型数据提取出来,可以减少数据库查询的次数。
用于多到一和多到多的关联查询
从表模型.objects.prefetch_related("关联主表模型名小写")
🍓 关联查询的筛选
Django会在被关联的模型中自动生成添加可以用于进行反向操作的属性
关联模型类名小写
# 查询图书,要求图书人物为“郭靖”
# 需要查询的为书籍信息,已知条件为人物信息
# 需要查询的为主表信息,已知条件为从表(外键定义所在的模型对应的表)信息
# 语法:
# filter(关联从表模型类名小写__字段名__运算符=值)
book = BookInfo.objects.filter(peopleinfo__name__exact='郭靖')
# 简写
book = BookInfo.objects.filter(peopleinfo__name='郭靖')
# 查询图书,要求图书中人物的描述包含"八"
book = BookInfo.objects.filter(peopleinfo__description__contains='
从表模型中有一个外键属性
# 需要查询的为人物信息,已知条件为书籍信息
# 需要查询的为从表信息,已知条件为主表信息
# 语法:
# filter(外键名__字段名__运算符=值)
# 查询书名为“天龙八部”的所有人物
people = PeopleInfo.objects.filter(book__name__exact='天龙八部')
# 简写
people = PeopleInfo.objects.filter(book__name='天龙八部')
# 查询图书阅读量大于30的所有人物
people = PeopleInfo.objects.filter(book__read_count__gt=30)
🍉 新增数据
🍒 方式一:实例化模型类,save()保存新增数据
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.实例化模型对象
写法1:实例化模型类型对象,并且在实例化的时候为属性赋值,会返回对应的新数据对象
book = BookInfo(
name='python',
pub_date='2000-01-01'
# 其他属性有默认值,这边就不进行赋值了
)
写法2:实例化模型类对象后,单独为实例化后的模型对象的属性赋值
book = BookInfo()
book.name = 'Java'
book.pub_date = '2001-01-01'
# 其他属性有默认值,这边就不进行赋值了
🌰 3.调用save()方法,将新增的数据对象同步到数据库中
book.save()
🍒 方式二:直接create()新增数据入库
对数据进行增删改查都可以通过调用模型类的模型管理类对象objects来实现
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.调用objects的create()方法直接新增数据对象入库
objects的create()方法会把新增的数据对象返回给我们
BookInfo.objects.create(
name='css3',
pub_date='2010-01-01'
# 其他属性有默认值,这边就不进行赋值了
)
🍉 更新数据
对数据进行增删改查都可以通过调用模型类的模型管理类对象objects来实现
🍒 方法一:获取模型对象修改对象属性,save()保存修改数据
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.获取模型对象
# 查询(获取)出需要进行修改的数据对象 获取id=1的数据对象
book = BookInfo.objects.get(id=1)
🌰 3.修改获取到的实例对象的属性
book.read_count = 2000
🌰 4.调用save()方法将修改后的数据同步数据库
book.save()
🍒 方法二:直接update()修改数据
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.获取模型对象时链式调用update()方法修改对象属性同时将修改后的数据同步到数据库
# 先过滤(filter)出需要进行修改的数据对象,然后修改对象属性
# 此方法会返回受影响的行数
BookInfo.objects.filter(id=1).update(
read_count = 100,
comment_count = 2000
)
get()方法得到的是一个模型对象,模型对象上不具有update()方法,所以不能使用get()方法得到模型对象后直接链式调用update()方法更新数据;而filter()方法返回的是一个QuerySet对象,QuerySet对象上具有update()方法,可以直接链式调用update()方法更新数据。
🍒 objects调用update()批量更新所有数据
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.使用objects直接调用update()批量更新所有数据对象(行)数据
该方法会返回数据库中受影响的行数
# 将所有数据对象(行)的read_count修改为500
books = BookInfo.objects.update(read_count=500)
🍒 批量更新多行数据
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.通过filter()方法过滤出多行数据,然后链式调用update()方法对过滤出来的多行数据对象进行批量更新
该方法会返回受影响的行数
books = BookInfo.objects.filter(read_count=1000).update(read_count=700)
🍉 删除数据
🍒 方法一:获取指定数据对象调用delete()删除该数据对象
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.获取指定的模型数据对象
book = BookInfo.objects.get(id=5)
🌰 3.获取到的模型数据对象调用delete()方法将自己删除
该方法会返回一个元组类型的数据,元组的第一个元素为本次操作删除的所有表的总行数之和,元组的第二个元素为字典类型,字典中为每个表在本次操作分别删除了几行数据
book.delete()
🍒 方法二:过滤出指定数据对象调用delete()删除过滤出来的数据对象
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.过滤出指定数据对象直接链式调用delete()方法删除过滤出来的数据对象
该方法会返回一个元组类型的数据,元组的第一个元素为本次操作删除的所有表的总行数之和,元组的第二个元素为字典类型,字典中为每个表在本次操作分别删除了几行数据
book = BookInfo.objects.filter(id=6).delete()
🍒 删除多行数据
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.过滤出指定数据对象直接链式调用delete()方法删除过滤出来的数据对象
该方法会返回一个元组类型的数据,元组的第一个元素为本次操作删除的所有表的总行数之和,元组的第二个元素为字典类型,字典中为每个表在本次操作分别删除了几行数据
books = BookInfo.objects.filter(read_count=700).delete()
🍒 删除全部数据
🌰 1.导入模型类:
from subapp01.models import BookInfo # 导入模型
🌰 2.使用objects调用all()方法查询出全部数据,然后调用delete()方法删除模型对应的表的全部数据对象
该方法会返回一个元组类型的数据,元组的第一个元素为本次操作删除的所有表的总行数之和,元组的第二个元素为字典类型,字典中为每个表在本次操作分别删除了几行数据
books = BookInfo.objects.all().delete()
🍉 执行原生SQL
当ORM提供的API无法实现数据的查询时,需要使用原生的SQL语句进行数据的查询,此时我们可以通过执行原生SQL实现数据的查询。
🍒 raw()
在Django中执行原生的SQL语句,我们需要使用raw()方法,raw()方法被定义在django.db.models.Manager
模块中。raw()方法返回的结果为RawQuerySet对象,对于RawQuerySet对象可以使用列表下标的方式获取其中的数据对象。
语法:
sql = '' # sql语句中使用 %s 作为占位符(防止SQL注入)
# 调用row()方法执行原生sql查询数据
模型类.objects.raw(sql, [填充sql中占位符的数据]) # 第二个参数可以使用列表
🌰
from subapp01.models import BookInfo
sql = """
select id, name
from bookinfo
where id = %s or read_count<=%s;
"""
books = BookInfo.objects.raw(sql, [1, 20])
>>> from subapp01.models import BookInfo
>>> sql = """
... select id, name
... from bookinfo
... where id = %s or read_count<=%s;
... """
>>> books = BookInfo.objects.raw(sql, [1, 20])
>>> books
<RawQuerySet:
select id, name
from bookinfo
where id = 1 or read_count<=20;
>
# 返回的结果集可以使用列表下标的方式获取数据对象
>>> books[0]
<BookInfo: 射雕英雄传>
>>> books[1]
<BookInfo: 笑傲江湖>
>>>
🍒 游标
在Django中,django.db.connection
中封装了数据库的连接对象,我们可以通过数据库的连接对象获取游标,然后通过获取的游标来执行原生SQL语句实现对数据库的增删改查。
🍓 用法
获取数据库的连接对象:
from django.db import connection
通过数据库的连接对象获取游标:
cursor = connection.cursor()
使用游标执行原生sql语句:
cursor.execute(sql, [填充占位符的数据])
关闭游标:
cursor.close()
🍓 插入数据
from django.db import connection
cursor = connection.cursor()
sql = """
insert into bookinfo(name, pub_date)
values (%s, %s);
"""
res = cursor.execute(sql, ('Java', '2020-11-11'))
cursor.close()
>>> from django.db import connection
>>> cursor = connection.cursor()
>>> sql = """
... insert into bookinfo(name, pub_date, read_count, comment_count, is_delete)
... values (%s, %s, %s, %s, %s);
... """
>>> res = cursor.execute(sql, ('Java', '2020-11-11', 100, 50, 0))
>>> res
<django.db.backends.sqlite3.base.SQLiteCursorWrapper object at 0x000002721C9BB0A0>
>>> cursor.close()
🍓 查询数据
游标对象提供了fetchall()方法用于获取执行sql语句后的全部数据,返回的结果为所有数据对象各字段数据组成的元组形成的列表;以及fetchone()方法用于获取其中的一个结果,第一次执行获取第一条数据记录,此后每执行一次都会返回下一条数据记录,直到所有的数据记录都获取过为止,每次返回的结果为数据对象各字段数据组成的元组。
from django.db import connection
sql = "select * from bookinfo;"
cursor = connection.cursor()
res = cursor.execute(sql)
data = res.fetchall()
cursor.close()
>>> from django.db import connection
>>> sql = "select * from bookinfo;"
>>> cursor = connection.cursor()
>>> res = cursor.execute(sql)
>>> res.fetchall()
[(8, '射雕英雄传', datetime.date(1980, 5, 1), 12, 34, False), (9, '天龙八部', datetime.date(1986, 7, 24), 36, 40, False), (10, '笑傲江湖', datetime.date(1995, 12, 24), 20, 80, False), (11, '雪山飞狐', datetime.d
ate(1987, 11, 11), 58, 24, False), (12, 'Java', datetime.date(2020, 11, 11), 100, 50, False)]
>>> cursor.close()
>>> from django.db import connection
>>> sql = "select * from bookinfo;"
>>> cursor = connection.cursor()
>>> res = cursor.execute(sql)
>>> res.fetchone()
(8, '射雕英雄传', datetime.date(1980, 5, 1), 12, 34, False)
>>> res.fetchone()
(9, '天龙八部', datetime.date(1986, 7, 24), 36, 40, False)
>>> res.fetchone()
(10, '笑傲江湖', datetime.date(1995, 12, 24), 20, 80, False)
>>> res.fetchone()
(11, '雪山飞狐', datetime.date(1987, 11, 11), 58, 24, False)
>>> res.fetchone()
(12, 'Java', datetime.date(2020, 11, 11), 100, 50, False)
>>> res.fetchone() # 此时以及获取完返回的全部数据记录,所以没有结果输出
>>> cursor.close()
🍓 更新数据
from django.db import connection
sql = "update bookinfo set name='python' where id=%s;"
cursor = connection.cursor()
res = cursor.execute(sql, [12])
res.rowcount # 获取本次操作在数据库中影响的行数
cursor.close()
>>> from django.db import connection
>>> sql = "update bookinfo set name='python' where id=%s;"
>>> cursor = connection.cursor()
>>> res = cursor.execute(sql, [12])
>>> res.rowcount
1
>>> cursor.close()
🍓 删除数据
from django.db import connection
sql = "delete from bookinfo where id=%s;"
cursor = connection.cursor()
res = cursor.execute(sql, [12])
res.rowcount # 获取本次操作在数据库中影响的行数
cursor.close()
>>> from django.db import connection
>>> sql = "delete from bookinfo where id=%s;"
>>> cursor = connection.cursor()
>>> res = cursor.execute(sql, [12])
>>> res.rowcount # 获取本次操作在数据库中影响的行数
1
>>> cursor.close()
🍉 事务处理
在Django中,提供了django.db.transaction
模块用于事务的处理。
🍒 装饰器方式
from django.db import transaction
@transaction.atomic # 装饰器
def fun(request):
save_id = transaction.savepoint() # 开启事务
try:
# 操作1
# 操作2
# ......
transaction.savepoint_commit(save_id) # 没有出现错误,提交从保存点到当前位置的所有操作
except:
transaction.savepoint_rollback(save_id) # 如果出现错误就回滚到保存点
🍒 with 语句方式
from django.db import transaction
def fun(request):
with transaction.atomic():
save_id = transaction.savepoint() # 开启事务
try:
# 操作1
# 操作2
# ......
transaction.savepoint_commit(save_id) # 没有出现错误,提交从保存点到当前位置的所有操作
except:
transaction.savepoint_rollback(save_id) # 如果出现错误就回滚到保存点