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的速度较快
 
 
posted @ 2023-05-19 17:00  启动CR  阅读(41)  评论(0)    收藏  举报