Django基础之多表查询

Django基础五之django模型层(二)多表操作

一.创建模型

表与表之间的关系,一对一,一对多,多对多

 

例如:

一对一:
author_s=models.OneToOneField(to='Author_s',to_field='id',on_delete=models.CASCADE)
       #Author类与Author_s类建立一对一关系,
       to指向表,to_field指向关联字段,
       on_delete级联删除--CASCADE为默认模式,如不需要默认级联删除,设置:on_delete=models.SET_NULL
       
       to_field和on_delete可以默认不写.
一对多
Publish=models.ForeignKey(to='Publish')
       #Book类与Publish类建立了多对一的关系,外键字段一般建立在 '多'的类 那一边,自动为int类型
多对多
Author=models.ManyToManyField(to='Author')
       #Book类与Author类建立了多对多关系

 

二.添加表记录

 

 

三.查询表记录(子查询)

总结:1正向查询--通过有外键的表的信息查询另外表信息

反向查询---通过别的表信息查询有外键表的信息

2.无论一对一,一对多,还是多对多,正向查询都是通过外键属性查询

反向查询:

一对一:直接通过表名查询 相应表对象.主键表名.查询属性

一对多:通过 表名_set 响应表对象.主键表名__set.查询属性

多对多:同一对多

    # 一对一
   #正向查询:查询id为4的作者的住址
   # author_obj = models.Author.objects.get(id=4)
   # print(author_obj.author_s_id.city)         #通过author_s_id这个外键属性

   # 逆向查询:查询在北京的作者的年龄
   # auth_obj=models.Author_s.objects.get(city='北京')
   # print(auth_obj.author.age) #直接通过 author表名


   # 一对多
   # 正向查询:查询id为8的书的出版社的名字
   # book_obj=models.Book.objects.get(id=8)
   # print(book_obj.publish_id.pname) #通过 publish_id 这个外键属性


   # 反向查询:查询id为2的出版社出版的书
   # publish_obj=models.Publish.objects.get(id=2)
   # print(publish_obj.book_set.all())           #通过 有外键的表的表名_set


   # 多对多
   # 正向查询:查询英语这本书的作者有哪些
   # book_obj=models.Book.objects.get(title='英语')
   # print(book_obj.author_id.all()) 通过 author_id 这个外键属性
   #
   # # 反向查询:查询何乌云写的书的名字
   # author_obj=models.Author.objects.filter(name='何乌云')[0]
   # ret=author_obj.book_set.all() #通过 有外键的表的表名_set
   # for i in ret:
   #     print(i.title,i.price)

related_name

  反向查询时,如果定义了related_name ,则用related_name替换 表名,例如:

 

# 练习: 查询人民出版社出版过的所有书籍的名字与价格(一对多)

# 反向查询 不再按表名:book,而是related_name:bookList


  queryResult=Publish.objects
              .filter(name="人民出版社")
              .values_list("bookList__title","bookList__price")

 

 

四.基于双下划线的跨表查询

基于双下划线的查询就一句话:正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表,一对一、一对多、多对多都是一个写法,注意,我们写orm查询的时候,哪个表在前哪个表在后都没问题,因为走的是join连表操作。

一对多
    正向:查询鹏too出版社出版的所有书籍的名字和价格

   ret=models.Book.objects
  .filter(publish__pname='鹏too出版社')   #通过 '__'告诉orm将Book表与Publish表join结合,
  #然后取 pname='鹏too出版社' 的信息
  #注意,因为是正向查询,所以这块的publish是属性,不是publish表
  .values('title','price')      #最后取想要的值
   print(ret)

   反向
   ret=models.Publish.objects.filter(pname='鹏too出版社').values('book__title','book__price')
   print(ret)
多对多
正向:查询何乌云出的所有的书的名字
ret=models.Book.objects.filter(author__name='何乌云').values('title')
print(ret)

反向
ret=models.Author.objects.filter(name='张鹏').values('book__title')
print(ret)
一对一
正向:查询赵子豪的手机号
ret=models.Author.objects.filter(name='赵子豪').values('author_s__phone')
反向:
ret=models.Author_s.objects.filter(author__name='赵子豪').values('phone')
连续跨表查询
连续跨表查询:查询飞much出版社出版的所有书籍的名字和作者的名字
方式一:通过Publish表
ret=models.Publish.objects.filter(pname='飞much出版社').values('book__title','book__author__name')       #'book__author__name',通过Publish表连											#接Book表,再连接Author表

方式二:通过Book表
ret=models.Book.objects.filter(publish__pname='飞much出版社').values('title','author__name')

方式三:通过Author表
ret=models.Author.objects.filter(book__publish__pname='飞much出版社').values('name','book__title')
聚合查询:aggregate(Avg..,Max..)

aggregate()是QuerySet 的一个终止子句,意思是说,它返回一个包含一些键值对的字典。键的名称是聚合值的标识符,值是计算出来的聚合值。键的名称是按照字段和聚合函数的名称自动生成出来的。如果你想要为聚合值指定一个名称,可以向聚合子句提供它。

ret=models.Book.objects.all().aggregate(Avg('price'))  #{'price__avg': 130.0}
ret=models.Book.objects.all().aggregate(Max('price'))
ret=models.Book.objects.all().aggregate(Min('price'))
ret=models.Book.objects.all().aggregate(Min('price'),Max('price'))
F查询

作用:对两个字段的值做比较

F查询:查询出评论大于大赞的书的名字

ret=models.Book.objects.filter(commentNum__gt=F('zanNum'))



ret=models.Book.objects.filter(title__endswith='赵').values('title')

ret= models.Book.objects.filter(price__range=[100.00,200.00]).values('title','price')

models.Book.objects.all().update(price=F('price')+1)
print(ret)
Q查询

执行更复杂的查询

Q 对象可以使用&(与) 、|(或)、~(非)操作符组合起来。当一个操作符在两个Q 对象上使用时,它产生一个新的Q 对象。

ret=models.Book.objects.filter(Q(commentNum__gt=10) & Q(zanNum__lt=20)).values('title')
ret=models.Book.objects.filter(Q(commentNum__gt=10) | Q(zanNum__lt=20)).values('title')
ret=models.Book.objects.filter(Q(commentNum__gt=10) | ~Q(zanNum__lt=20)).values('title')

 

分组查询

注意:annotate里面必须写个聚合函数,不然没有意义,并且必须有个别名=,别名随便写,但是必须有,用哪个字段分组,values里面就写哪个字段,annotate其实就是对分组结果的统计,统计你需要什么。

#*****分组查询
查询每个出版社出版了多少本书
单表查询
ret=models.Book.objects.values('publish').annotate(num=Count('id'))

查询每个出版社名称以及其出版书对应的数量
多表查询
ret=models.Book.objects.values('publish__pname').annotate(num=Count('id'))

ret=models.Publish.objects.annotate(num=Count('book')).values('pname','num')

 

五.orm执行原生sql语句(了解)

在模型查询API不够用的情况下,我们还可以使用原始的SQL语句进行查询。

Django 提供两种方法使用原始SQL进行查询:

一:一种是使用raw()方法,进行原始SQL查询并返回模型实例;

二:完全避开模型层,直接执行自定义的SQL语句。

 

raw()查询:必须包含主键(primary key)
#row管理器方法,查询自己的表格信息
for i in  models.Book.objects.raw('select * from app01_book'):
    print(i.title,i.price)
# 
# 查询其他表的信息
for i in  models.Book.objects.raw('select * from app01_author'):
    print(i.name,i.age)

直接执行自定义SQL

  有时候raw()方法并不十分好用,很多情况下我们不需要将查询结果映射成模型,或者我们需要执行DELETE、 INSERT以及UPDATE操作。在这些情况下,我们可以直接访问数据库,完全避开模型层。

  我们可以直接从django提供的接口中获取数据库连接,然后像使用pymysql模块一样操作数据库。

from django.db import connection,connections      #导入模块
cursor=connection.cursor()					  #获取数据库句柄
cursor.execute("""select * from app01_author""")	#执行想要执行的语句
ret=cursor.fetchone()        #从cursor记录的多条信息中提取一条
print(ret)

六. Python脚本中调用Django环境(django外部脚本使用models)

import  os                       #调用os模块

if __name__ == '__main__': 
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "manytables.settings")  #配置django的环境变量
    import django
    django.setup()			  #调用开启django

    from app01 import models			

    ret=models.Author.objects.filter(id=3).values('name')
    print(ret)

 

posted @ 2019-05-29 22:33  socoolonly1  阅读(221)  评论(0)    收藏  举报