Django-06(模型层(ORM语法):跟数据库打交道的)
一、单表查询(增删改查):
1、配置数据库测试环境:
1.1、 models.py文件:
from django.db import models # Create your models here. class User(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() register_time = models.DateField() # 年月日 """ DateField DateTimeField 两个重要参数 auto_now:每次操作数据的时候 该字段会自动将当前时间更新 auto_now_add:在创建数据的时候会自动将当前创建时间记录下来 之后只要不认为的修改 那么就一直不变 """ def __str__(self): return '对象:%s'%self.name class Book(models.Model): title = models.CharField(max_length=32) price = models.DecimalField(max_digits=8,decimal_places=2) publish_date = models.DateField(auto_now_add=True) # 一对多 publish = models.ForeignKey(to='Publish') # 多对多 authors = models.ManyToManyField(to='Author') class Publish(models.Model): name = models.CharField(max_length=32) addr = models.CharField(max_length=64) email = models.EmailField() # varchar(254) 该字段类型不是给models看的 而是给后面我们会学到的校验性组件看的 def __str__(self): return '对象:%s'%self.name class Author(models.Model): name = models.CharField(max_length=32) age = models.IntegerField() # 一对一 author_detail = models.OneToOneField(to='AuthorDetail') class AuthorDetail(models.Model): phone = models.BigIntegerField() # 电话号码用BigIntegerField或者直接用CharField addr = models.CharField(max_length=64)
1.2、执行models.文件代码:
1、cd 切换到项目路径中 2、执行:python3 manage.py makemigrations #此步只是在将操作记录到小本本上(migrations文件夹内) 不能真正的直接操作数据库 3、python3 manage.py migrate # 将操作真正的同步到数据库中 """只要在models中书写了跟数据库相关的代码 就必须要重新执行上述两条命令"""
1.3、配置测试文件代码准备数据:
在django中,如果只是想写脚本,不是写前后交互的代码 脚本代码在应用下的哪个tests文件都可以,但是先配置,在manage.py中前四行代码拷贝过来 #!/usr/bin/env python import os if __name__ == "__main__": os.environ.setdefault("DJANGO_SETTINGS_MODULE", "My_orm.settings") import django django.setup() # 在这个代码块的下面就可以测试django里面的单个py文件了
2、测试例子:
from app01 import models # user = models.User.objects.all() # print(user.query) """ 被关联的表需要先增加数据,增加后,才能关联 """ # 1、增 # import datetime # ctime = datetime.datetime.now() # print(ctime) # 1.1 method on # res = models.User.objects.create(name='柏拉图',age=24,register=ctime) # print(res) # 1.2 method two # user_obj = models.User(name='蒋介石',age=140 ,register='1883-02-22') # print(user_obj) # user_obj.save() # 2、删 """ pk会自动查询表的主键 指代的就是当前表的主键字段 用了pk之后 你就不需要指代当前表的主键字段到底叫什么了 uid pid sid """ # 1.1 method one:涉及批量删除 # res = models.User.objects.filter(pk=6).delete() # print(res) # 1.2 method two # user_obj = models.User.objects.filter(pk = 3).first() # print(user_obj) # user_obj.delete() # 3、改 # 3.1 method one # models.User.objects.filter(pk=7).update(name = '仔仔') # 3.2 method two # user_obj = models.User.objects.filter(pk=7).first() # user_obj.name = '毛毛' # user_obj.save() # 4、查 # 1.1 query all # user_obj = models.User.objects.all() # print(user_obj) # 1.2 filter # user_obj = models.User.objects.filter(pk=7).first() # print(user_obj.name,user_obj.age,user_obj.register) # 1.2.1 filter all # user_all =models.User.objects.filter() # print(user_all) # 1.3 get 筛选条件 """ get 是返回当前数据对象 """ # get_all = models.User.objects.get(pk =2) # print(get_all)
二、常见的十几种查询方法:
1、13种常用查询方法及解释
1、all() 查询所有数据
2、filter() 带条件过滤,同时括号内为空,效果与all一样
3、get() 带有条件的过滤方法,但是如果查询没有,会报错
4、first()
5、last()
7、values() : 作用可以指定获取数据的字段 类似与mysql: select name, age from table
8、values_list():列表套元组
9、distinct()去重,与sql语句中distinct 相似
"""
sql中的distinct 的用法:
SELECT DISTINCT name FROM app01_user where name = '姗姗' 不加distincy SELECT * FROM app01_user where name = '姗姗' 注意: distinct 使用不能带有主键,因为主键是唯一的,unique,加上主键就不能组合成唯一了
"""
10、order_by()
10.1 默认升序:
数字从小往下排列,与sql中 SELECT * FROM app01_user ORDER BY age ASC 一致 res = models.User.objects.order_by('age') print(res.values('name','age'))
10.2 降序升序:
数字从大往小排列,与sql中 SELECT * FROM app01_user ORDER BY age DESC 一致 """ 总结: 升序: order_by('age') 降序: order_by('-age'):在字段前缀加- """
11、count():统计个数 """ sql 语句: SELECT COUNT(*) AS `__count` FROM `app01_user` """ #
12、exclude(): 类似于sql中的not 和not in
SELECT `app01_user`.`id`, `app01_user`.`name`, `app01_user`.`age`, ` app01_user`.`register` FROM `app01_user` WHERE NOT (`app01_user`.`name` = '姗姗') LIMIT 21;
13、exists():判断布尔值的,不过用的比较少,python查询语句自带布尔值
2 、配置所以查询方式都可以使用query的方法
2.1setting.py
# 方式2:所有的sql语句都能查看 # 去配置文件中配置一下即可 LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } }
3、详情使用例子:
常见的十几种查询方法 # 1、all() 查询所有数据 # 2、filter() 带条件过滤,同时括号内为空,效果与all一样 # 3、get() 带有条件的过滤方法,但是如果查询没有,会报错 # get_user = models.User.objects.get(pk=7) # print(get_user) # 4、first() # user_obj = models.User.objects.all().first() # print(user_obj) # 5、last() # user_obj = models.User.objects.all().last() # print(user_obj) # 7、values() : 作用可以指定获取数据的字段 类似与mysql: select name, age from table # 7.1 method one # res = models.User.objects.values('name','age','register') # print(res) # 7.2 METHOD TWO # res = models.User.objects.filter(pk=5).values('pk','name','age','register') # print(res) # 8、values_list():列表套元组 res = models.User.objects.values_list('pk','name','age','register') print(res.query) # <QuerySet [(1, '姗姗', 34, datetime.date(2023, 4, 24)), (4, '红红', 24, datetime.date(2023, 4, 24)), (5, '牛牛', 300, datetime.date(2023, 4, 24)), (7, '莎莎', 130, datetime.date(2023, 4, 24)), (8, 'lili', 140, datetime.date(2023, 4, 24))]> """ 拓展: .queey 可以查看查询的sql语句,***仅限于查,并且只支持queryset对象, 但是非queryset对象也想查看怎么办呢,给出配置放在setting的任意位置 配置信息: LOGGING = { 'version': 1, 'disable_existing_loggers': False, 'handlers': { 'console':{ 'level':'DEBUG', 'class':'logging.StreamHandler', }, }, 'loggers': { 'django.db.backends': { 'handlers': ['console'], 'propagate': True, 'level':'DEBUG', }, } } """ # 9、distinct()去重,与sql语句中distinct 相似 """ sql中的distinct 的用法: SELECT DISTINCT name FROM app01_user where name = '姗姗' 不加distincy SELECT * FROM app01_user where name = '姗姗' 注意: distinct 使用不能带有主键,因为主键是唯一的,unique,加上主键就不能组合成唯一了 """ # res = models.User.objects.values('name','pk').distinct() # print(res) # 10、order_by() # 10.1 默认升序:数字从小往下排列,与sql中 SELECT * FROM app01_user ORDER BY age ASC 一致 # res = models.User.objects.order_by('age') # print(res.values('name','age')) # 10.1 降序升序:数字从大往小排列,与sql中 SELECT * FROM app01_user ORDER BY age DESC 一致 """ 总结: 升序: order_by('age') 降序: order_by('-age'):在字段前缀加- """ # res = models.User.objects.order_by('-age') # print(res.values('name','age')) # 11、count():统计个数 """ sql 语句: SELECT COUNT(*) AS `__count` FROM `app01_user` """ # res = models.User.objects.count() # print(res) # res = models.User.objects.filter(name='姗姗').count() # print(res) # sql语句:SELECT COUNT(*) AS `__count` FROM `app01_user` WHERE `app01_user`.`name` = '姗姗'; # 12、exclude(): 类似于sql中的not 和not in """ # SELECT `app01_user`.`id`, `app01_user`.`name`, `app01_user`.`age`, `app01_user`.`register` FROM `app01_user` WHERE NOT (`app01_user`.`name` = '姗姗') LIMIT 21; """ # res = models.User.objects.exclude(name='姗姗') # print(res) # 13、exists():判断布尔值的,不过用的比较少,python查询语句自带布尔值 # res = models.User.objects.filter(pk=3).exists() # print(res) # 自带返回值: # res = models.User.objects.filter(pk=3) # if res: # print('我是True') # else: # print('我是falase') # 14、reverse()反转的前提是 数据已经排过序了 order_by() # res = models.User.objects.all() # res1 = models.User.objects.order_by('age').reverse() # print(res,res1)
三、神奇的双下划线查询
1、介绍:
""" 1、什么是神奇的下划线? 1、是帮助我们更好的筛选数据的方式,相当于对where的补充 1、13中查询方法all(),filter(),get(),first(),last(),values(),values_list() distinct(),order_by(),reverse(),count(),existe(),exclde()相当于是第一层排除 补充reverse(),是需要排序之后使用才能生效的 2、相比第一层筛选,下划线多了什么东西,双下划线相当于where 条件? 1、大于、小于 ==》 > < greater than lass than 2、大于等于 、小于等于 ==> >= <= 3、或 ==> or 4、之间 ==> WHERE salary BETWEEN 10000 AND 20000; where salary >=10000 or salary<=20000; 5、模糊查询 ==》like 6、区分大下写 7、时间筛选 """
2、下划线例子-大于:
user_obj = models.User.objects.filter(age__gt=100) #age > 100 """ 相当于 sql: select * from User where age > 100; """ print(user_obj)
3、下划线例子-小于:
# 小于: user_obj = models.User.objects.filter(age__lt= 100) #相当于 age<100 print(user_obj) """ 相当于 sql: select * from User where age < 100; """
4、下划线例子-大于等于
user_obj = models.User.objects.filter(age__gte=300) #age >= 100 """ 相当于 sql: select * from User where age >= 100; """ print(user_obj)
5、下划线例子-小于等于
user_obj = models.User.objects.filter(age__lte= 34) #相当于 age<100 print(user_obj) """ 相当于 sql: select * from User where age < 100; """
6、下划线例子-in的用法
user_obj = models.User.objects.filter(age__in=[24,34,300]) print(user_obj) """ 相当于 sql: select * from User where age in [24,34,300]; """
7、下划线例子-之间
# user_obj = models.User.objects.filter(age__range=[1,300]) # print(user_obj) """ 相当于sql: select * from user where age between 1 and 300; 或者 select * from user where age>=1 and age<=300; """
8、下划线例子-模糊匹配之包含
# 模糊匹配之包含:包含的意思是,不在开头和末尾,就在中间 # user_obj = models.User.objects.filter(name__contains='I') # print(user_obj) """sql: select * from user where name like "%i%" """
9、下划线例子-模糊匹配之忽略区分大小写
# 模糊匹配之区分大小写:忽略大小写的关键就在下划线后缀词语的前面加i # user_obj = models.User.objects.filter(name__icontains='I') # print(user_obj) """sql: 自动忽略大小写 """
10、下划线例子-模糊匹配之开头匹配
# 模糊匹配之开头匹配:startswith # user_obj = models.User.objects.filter(name__startswith = 'li') # print(user_obj) """ sql:select * from user where name like 'li%' python str语句: str1 = 'my name is python' str1.startswith('my') """
11、下划线例子-模糊匹配之末尾匹配
# 模糊匹配之末尾匹配:endswith # user_obj = models.User.objects.filter(name__endswith = 'li') # print(user_obj) # """ # sql:select * from user where name like '%li' # # python str语句: str1 = 'my name is python' # str1.endswith('my')
12、下划线例子-查询日期
查询日期 按照年份查 user_obj1 = models.User.objects.filter(register__year = '1989') 按照月份查 user_obj2 = models.User.objects.filter(register__month='9') 按照天查 user_obj3 = models.User.objects.filter(register__day='24') 工作日 user_obj4 = models.User.objects.filter(register__week_day='1') 精确查找 user_obj5 = models.User.objects.filter(register__exact='1989-09-24') print(user_obj1) print(user_obj2) print(user_obj3) print(user_obj4) print(user_obj5)
时间拓展:
各个时间总结:
四、多表操作-外键字段的增删改查:
1、一对多外键增删改查:
1、增
publish = models.Publish.objects.create(name='北方出版社', addr='河北', email='llxxs@gmail.com') print(publish) models.Book.objects.create(title='梅花',price=99.99,publish_date='1498-09-18',publish_id=3) models.Book.objects.create(title='春宫图',price=99.99,publish_date='1598-09-18',publish_id=3) 2 虚拟字段 对象 外键就不能加_id了 publish_obj = models.Publish.objects.filter(pk=3).first() print(publish_obj) models.Book.objects.create(title='草民简史', price=99.99, publish_date='1598-09-18', publish=publish_obj)
2、删:
models.Book.objects.create(title='太监简史',price=99.99,publish_date='1598-09-18',publish_id=4) 级联删除 publish_obj = models.Publish.objects.filter(pk=4).delete() # 级联删除 models.Book.objects.filter(pk=4).delete() # 级联删除
3、改
1、直接修改 models.Book.objects.filter(pk=5).update(publish_id=2) 2、虚拟字段修改 publish_obj = models.Publish.objects.filter(pk=5) print(publish_obj.first()) models.Book.objects.filter(pk=6).update(publish = publish_obj.first() )
2、多对多 增删改查:
1、增:如何给书籍添加作者?
book_obj = models.Book.objects.filter(pk=7).first() print(book_obj.author.all()) # 就类似于你已经到了第三张关系表了 book_obj.author.add(3) # 书籍id为1的书籍绑定一个主键为1 的作者 book_obj.author.add(1,2,3) """ 通过这种方式就可以给第三张表添加关联信息,前提是你两张被关联的外键表数据已经建立好 """ # 给数据添加作者虚拟对象 # 1、建立多个authorDetail添加多条数据 # models.AuthorDetail.objects.create(phone=1111111,addr='库页岛') # models.AuthorDetail.objects.create(phone=2222222, addr='广岛') # models.AuthorDetail.objects.create(phone=3333333, addr='长崎') # models.AuthorDetail.objects.create(phone=4444444, addr='琉球') # models.AuthorDetail.objects.create(phone=5555555, addr='北海道') # models.AuthorDetail.objects.create(phone=6666666, addr='多伦多') # models.AuthorDetail.objects.create(phone=777777, addr='大阪') # models.AuthorDetail.objects.create(phone=8888888,addr='东京') # 2、建立个人信息,外键虚拟关联 # author_datail_obj1 = models.AuthorDetail.objects.filter(pk=6).first() # # res = models.Author.objects.create(name='清水键',age=40,author_detail=author_datail_obj1) # # print(res) # 3、添加出版社信息 # models.Publish.objects.create(name='东京出版社',addr='东京',email='dongjing@email.com') # models.Publish.objects.create(name='新加坡出版社', addr='新加坡', email='xinjiapo@email.com') # models.Publish.objects.create(name='辽宁出版社', addr='辽宁', email='liaoning@email.com') # models.Publish.objects.create(name='西安出版社', addr='西安', email='xian@email.com') # models.Publish.objects.create(name='长沙出版社', addr='长沙', email='changsha@email.com') # models.Publish.objects.create(name='东莞出版社', addr='东莞', email='dongguan@email.com') # models.Publish.objects.create(name='深圳出版社', addr='深圳', email='shenzheng@email.com') # models.Publish.objects.create(name='武汉出版社', addr='武汉', email='wuhang@email.com') # models.Publish.objects.create(name='青岛出版社', addr='青岛', email='qingdao@email.com') # models.Publish.objects.create(name='济南出版社', addr='济南', email='jinan@email.com') # models.Publish.objects.create(name='上海出版社', addr='上海', email='shanghai@email.com') # 4 、添加书籍信息。 # publish_obj1 = models.Publish.objects.filter(name='东京出版社').first() # models.Book.objects.create(title='飞猪',price=88.67,publish_date='1996-05-23',publish=publish_obj1) # models.Book.objects.create(title='菊与刀',price=88.67,publish_date='2001-05-23',publish=publish_obj1) # models.Book.objects.create(title='人间失格',price=85.67,publish_date='2001-05-23',publish=publish_obj1) # models.Book.objects.create(title='心',price=84.67,publish_date='2022-05-23',publish=publish_obj1) # models.Book.objects.create(title='干法',price=83.67,publish_date='2011-05-23',publish=publish_obj1) # models.Book.objects.create(title='挪威的森林',price=188.67,publish_date='19991-05-23',publish=publish_obj1) # models.Book.objects.create(title='拥抱战败',price=888.67,publish_date='2014-05-23',publish=publish_obj1) # models.Book.objects.create(title='最新支那要人传',price=848.67,publish_date='2001-05-23',publish=publish_obj1) # 5、书籍和个人信息多对多关联 # author_obj1 = models.Author.objects.filter(pk=1).first() """ 如果不加firs() TypeError: int() argument must be a string, a bytes-like object or a number, not 'QuerySet' """ # author_obj2 = models.Author.objects.filter(pk=2).first() # author_obj3 = models.Author.objects.filter(pk=3).first() # author_obj7 = models.Author.objects.filter(pk=7).first() # author_obj8 = models.Author.objects.filter(pk=8).first() # # book_obj1 = models.Book.objects.filter(pk=11).first() # res = book_obj1.author.add(author_obj1,author_obj2,author_obj3,author_obj7,author_obj8) """ add给第三张关系表添加数据 括号内既可以传数字也可以传对象 并且都支持多个 """
2、删
remove 括号内既可以传数字也可以传对象 并且都支持多个
# 1、直接添加外键id # book_obj1 = models.Book.objects.filter(pk=11).first() # book_obj1.author.remove(1,2,3) # 2、删除对象 """ remove 括号内既可以传数字也可以传对象 并且都支持多个 """ # book_obj1 = models.Book.objects.filter(pk=11).first() # # author_obj7 = models.Author.objects.filter(pk=7).first() # author_obj8 = models.Author.objects.filter(pk=8).first() # # book_obj1.author.remove(author_obj7, author_obj8)
3、改:
""" set 括号内必须传一个可迭代对象,该对象内既可以数字也可以对象 并且都支持多个 """ # 清空: book_obj1.author.clear() # 在第三张关系表中清空某个书籍与作者的绑定关系
# book_obj1 = models.Book.objects.filter(pk=9).first() # book_obj1.author.set([1,2]) #清空 # book_obj1 = models.Book.objects.filter(pk=3).first() # # book_obj1.author.clear()
五、正反向的概念
# 正向 # 反向 外键字段在我手上那么,我查你就是正向 外键字段如果不在手上,我查你就是反向 book >>>外键字段在书那儿(正向)>>> publish publish >>>外键字段在书那儿(反向)>>>book 一对一和多对多正反向的判断也是如此 """ 正向查询按字段 反向查询按表名小写 _set ... """
六、跨表查询(重点)
1、子查询:
1.查询书籍主键为1的出版社----正向查询 book_obj1 = models.Book.objects.filter(pk=3).first().publish print(book_obj1) print(book_obj1.name) print(book_obj1.addr) print(book_obj1.email) 2.查询书籍主键为2的作者 book_obj1 = models.Book.objects.filter(pk=5).first() print(book_obj1.author) #app01.Author.None print(book_obj1.author.all()) #, , ]> 3.查询作者'清水键'的电话号码 author_obj1 = models.Author.objects.filter(name='清水键').first() author_obj1 = author_obj1.author_detail print(author_obj1.phone) 4.查询出版社是东方出版社出版的书 publish_obj = models.Publish.objects.filter(name='太原出版社').first() # 反向查找加_set res = publish_obj.book_set print(res.all()) for i in res.all(): print(i.title) 5.查询作者是elon写过的书-反向 author_obj = models.Author.objects.filter(name='elon').first() res = author_obj.book_set print(res.all()) for i in res.all(): print(i.title) 6.查询手机号是110的作者姓名-反向 authorDetail_obj =models.AuthorDetail.objects.filter(phone= 3333333).first() res = authorDetail_obj.author # 因为是一对一不是集合不需要加_set print(res.name)
""" 基于对象: 1、反向查询的时候,表对象需要小写; 2、如果对象是多个,需要加_set.all()例如一对多、多对多的场景 3、如果对象是一个,例如一对一,或者多对一的情况下,不需要加_set """
2、联表查询:
1.查询wz1的手机号和作者姓名 1.1正向查找 res = models.Author.objects.filter(name='wz1').values('name','author_detail__phone') print(res) 1.2 反向查找 res = models.AuthorDetail.objects.filter(author__name= 'wz1').values('author__name','phone') print(res) 2.查询书籍主键为1的出版社名称和书的名称: 2.1正向查找 res = models.Book.objects.filter(pk = 6).values('publish__name','title') print(res) 2.2 反向查找 res = models.Publish.objects.filter(book__pk = 6).values('name','book__title') print(res) 3.查询书籍主键为1的作者姓名: 3.1正向查找 res = models.Book.objects.filter(pk = 6).values('author__name') print(res) 3.2反向查找 res = models.Author.objects.filter(book__pk = 6).values('name') print(res) 4.查询书籍主键是1的作者的手机号 4.1正向查找 res = models.Book.objects.filter(pk = 6).values('author__author_detail__phone') print(res) 4.2反向查找 res = models.AuthorDetail.objects.filter(author__book__pk = 6).values('phone') print(res)
七、聚合查询:
1、什么是聚合查询:aggregate
对分组后的数据进行统计aggregate,单词也是汇集的意思,类似于聚合统计 与 select max(price),min(price),sum(price),count(price),avg(price) from Book group by age
2、如何使用?有什么用?
1、先导入聚合函数 from django.db.models import Max, Min, Count, Sum, Avg models.Book.object.aggregate(Avg('price')) 作用是对分组后进行统计操作,如果不加具体的值,就是对本表分组,其实也就是不分组 如果我想按照指定的字段分组该如何处理呢? models.Book.objects.values('price').annotate() 后续BBS作业会使用
3、例子
from django.db.models import Max,Min,Sum,Count,Avg # res = models.Book.objects.aggregate(Max('price'),Min('price'),Sum('price'),Count('price'),Avg('price')) # print(res)
八、分组查询
1、什么是分组?
1、就是对某个字段进行分组,例如性别,再统计各性别的人 2、在django中跨表就是对主表id分组
2、如何使用?有什么用?
分组后可以对某个分组后的数据进行统计操作
3、例子:
3.1 统计每一本书的作者个数:
# 加上annotate(author_num=Count('author')) 就是连接author ,且对Book.id进行分组,再对author_book.book_id进行聚合函数统计.
annotate:准确的来说两个作用,起别名,聚合函数统计
res=models.Book.objects.annotate(author_num=Count('author')).values('title','author_num') print(res) """ author_num是我们自己定义的字段 用来存储统计出来的每本书对应的作者个数 sql语句: SELECT app01_book.title,COUNT(app01_book_author.author_id) FROM app01_book LEFT JOIN app01_book_author ON app01_book.id = app01_book_author.book_id GROUP BY app01_book.id 加上having后可以过滤掉 HAVING COUNT(app01_book_author.author_id) >0 """
3.2.统计每个出版社卖的最便宜的书的价格:
# 2.1 django写法 # res = models.Publish.objects.annotate(mix_price = Min('book__price')).values('name','mix_price') # print(res) """ 目前无法实现多个条件 """ """ sql: SELECT app01_publish.name , min(app01_book.price) FROM app01_book RIGHT JOIN app01_publish ON app01_book.publish_id = app01_publish.id GROUP BY app01_publish.id HAVING COUNT(app01_book.publish_id ) > 0 """
3.3.统计不止一个作者的图书:
# 3.统计不止一个作者的图书 # res = models.Book.objects.annotate(count_author = Count('author')).filter(count_author__gt = 1).values('title','count_author') # print(res) """ sql: SELECT app01_book.title , COUNT(app01_book_author.book_id) FROM app01_book LEFT JOIN app01_book_author ON app01_book.id = app01_book_author.book_id GROUP BY app01_book.id """
3.4.查询每个作者出的书的总价格:
# 4.查询每个作者出的书的总价格 # res = models.Author.objects.annotate(sum_price = Sum('book__price')).values('name','sum_price') # print(res) """ sql: SELECT t1.`name`,sum(t3.price) FROM app01_author as t1 LEFT JOIN app01_book_author as t2 ON t1.id = t2.author_id LEFT JOIN app01_book as t3 ON t2.book_id = t3.id GROUP BY t1.id """ """ 如果我想按照指定的字段分组该如何处理呢? models.Book.objects.values('price').annotate() 后续BBS作业会使用 你们的机器上如果出现分组查询报错的情况 你需要修改数据库严格模式 """
九、F与Q查询
1、什么是F与Q查询
F查询(Full-text search query)和Q查询(Query Expansion)是搜索引擎中常用的两种查询类型。 F查询是一种基于关键词的查询方式,它通过匹配文本中的关键词来找到与查询相匹配的结果。F查询通常是使用 全文索引实现的,可以在文本中快速查找关键词并返回相关结果。例如,在使用Google搜索引擎时,您可以输入 关键词并按下搜索按钮,然后搜索引擎将返回与关键词相关的结果。 Q查询是一种扩展查询方式,它会自动将查询词扩展为与其相关的其他词汇。例如,在搜索引擎中,当您搜索“苹果”时 ,Q查询会将其扩展为与“苹果”相关的其他词汇,如“iPhone”、“iPad”、“MacBook”等,以便返回更全面的搜索结 果。Q查询通常使用语言模型和统计算法实现,可以根据搜索历史和用户偏好对查询进行自动扩展。 F查询和Q查询通常会在搜索引擎中同时使用,以便在搜索结果中返回相关且具有高质量的内容。
2、如何使用?有什么用?
F:是关键字查询,用于比较大小和拼接数字,拼接字符串 拼接字符串需要其他函数参与 from django.db.models.functions import Concat Concat(F('title'),Value('爆款'),Value('爆款')) Q:是可以执行与,或,非的功能 """ 1、 或: Q(sales__gt=100)|Q(stock__lt=600) 2、 and: Q(sales__gt=100),Q(stock__lt=600) 3、 非: ~Q(maichu__gt=100)|Q(price__lt=600) """
3、F: 比较大小,查询卖出数大于库存数的书籍
from django.db.models import F # res = models.Book.objects.filter(sales__lt= F('stock') ).values('title','sales','stock') # # print(res) """ sql: select * from book where sales > stock """
4、F: 数字加减,将所有书籍的价格提升500块
# models.Book.objects.filter().update(price = F('price') + 500)
5、F: 字符拼接:将所有书的名称后面加上爆款两个字
from django.db.models.functions import Concat from django.db.models import Value models.Book.objects.filter().update(title = Concat(F('title'),Value('爆款'),Value('爆款'))) """ sql: update app.book set 'title' = concat_ws ('','title','爆款') """ from django.db.models.functions import Concat from django.db.models import Value,Q # models.Book.objects.filter(pk=3).update(title = F('title') + 'sb') # 不通过Values会报错
6、Q查询-或:查询卖出数大于100或者价格小于600的书籍
""" 1、 或: Q(sales__gt=100)|Q(stock__lt=600) 2、 and: Q(sales__gt=100),Q(stock__lt=600) 3、 非: ~Q(maichu__gt=100)|Q(price__lt=600) """ # res = models.Book.objects.filter(Q(sales__gt=100)|Q(stock__gt=600)) # for i in res: # print(i.title) """ select * from book where sales > 100 or stock < 600; """
7、Q查询-Q的高阶用法
Q的高阶用法 能够将查询条件的左边也变成字符串的形式: # q = Q() # q.connector = 'or' #可以修改or 或者 and # q.children.append(Q(sales__lt=400)) # q.children.append(Q(stock__gt=600)) # res = models.Book.objects.filter(q) # for i in res: # print(i.title)
十、Django开启事务
a c1、什么是事务
# 事务 """ mysql-事务: 1、开启事务,是为了某个事物,或者说某个任务能够全部完成,例如a向b转账,就需要在a先扣钱,b增加,这个过程全部完成后,这个事务才算成功 2、事务的本质是确保数据安全,如果成功才正式提交,commit,如果失败就回滚 3、在mysql中事务开启关闭的方式为: start transaction; select * from employee where name = "egon"; update employee set age=age+1 where name = "egon"; commit; ROLLBACK:取消当前事务所做的更改 #回滚 """ """ pymsql try: cursor.execute(sql_1) cursor.execute(sql_2) cursor.execute(sql_3) except Exception as e: connect.rollback() # 事务回滚 print('事务处理失败', e) else: connect.commit() # 事务提交 print('事务处理成功', cursor.rowcount)# 关闭连接 cursor.close() connect.close() """
2、如何使用?有什么用?
开启事务 from django.db import transaction try: with transaction.atomic(): pass except Exception as e: connect.rollback()
十一、orm中常用字段及参数
十二、数据库查询优化(only与defer、select_related与prefetch_related)
1、惰性执行:
惰性测试 res = models.Book.objects.all() print(res) #需要的时候才会走查询 for i in res: # print(i.price) 1、不用的时候不执行 2、for 循环的时候每次都会执行一次
2、 only与defer
1、only:
only 用于单个字段查询,对查询对象遍历的时候,查询筛选的字段,不会重复查询 res = models.Book.objects.only('title') for i in res: print(i.title) 因为已经筛选条件就是(‘title’),在筛选的时候,已经将‘title’对象数据存储,再遍历拿的时候,只需要在对象中那就行
2、defer:
defer: res = models.Book.objects.defer('title') # print('2222',res) # for i in res: print(i.price) 与only相反,括号内放的字段不在查询出来的对象里面,不需要重新走数据,在查询出来的对象里面的字段需要重新走查询
3、only与defer 的区别:
""" 所有查询都是惰性查询 only :仅括号内放的字段在查询出来的对象里面,不需要重新走数据,其他字段都需要重新走查询 defer: 与only相反,括号内放的字段不在查询出来的对象里面,不需要重新走数据,在查询出来的对象里面的字段需要重新走查询 """
3、select_related与prefetch_related:
1、惰性查询
select_related与prefetch_related 跟跨表操作有关 res = models.Book.objects.all() for i in res: print(i.publish.name) # 每循环一次就要走一次数据库查询
2、select_related:
select_related:是内连接查询,查询后将查询的对象放在对象里面,for遍历的时候,看起来只查询一次 res = models.Book.objects.select_related('authors') # INNER JOIN """ select_related内部直接先将book与publish连起来 然后一次性将大表里面的所有数据 全部封装给查询出来的对象 这个时候对象无论是点击book表的数据还是publish的数据都无需再走数据库查询了 select_related括号内只能放外键字段 一对多 一对一 多对多也不行 """ for i in res: print(i.publish.name) #现在每次循环都不需要再执行一次了
3、prefetch_related()
res = models.Book.objects.prefetch_related('publish') # 子查询 """ prefetch_related该方法内部其实就是子查询 将子查询查询出来的所有结果也给你封装到对象中 给你的感觉好像也是一次性搞定的 """ for i in res: print(i.publish.name)
4、select_related 和 prefrtch_related的优缺点比较
select_related是内连接、prefrtch_related子查询 在表特别多的时候,prefrch_related查询相对较好,因为select_related连表花的时间较多 在表不是特别多的情况下,select_related的速度较快
浙公网安备 33010602011771号