🍒 聚合函数
在查询数据时需要使用聚合函数,则需要使用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) # 如果出现错误就回滚到保存点