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)

浙公网安备 33010602011771号