ORM的多表查询

ORM最核心与用的最多的地方就是跨表查询了。这里的“跨表查询”分为以下几种:基于对象的跨表查询基于双下划线的跨表查询聚合查询F与Q查询以及分组查询
下面就为大家详细阐述这几种查询的具体细节及用法。
另外,本文省去了Django与MySQL数据库之间建立连接以及创建表、添加表记录的过程。如果大家有兴趣可以回顾下我之前的两篇文章:

https://www.cnblogs.com/paulwhw/p/9395085.html

https://www.cnblogs.com/paulwhw/p/9405168.html

本文在这两篇文章的基础上进行详述。

基于对象的跨表查询

基于对象的跨表查询最终翻译成我们的SQL语句其实是子查询的语句,也就是说我们利用一个查询的结果作为另外一个查询的条件进行查询。数据库中的一个表记录其实就是筛选出来的“对象”的一个对象————可以利用.操作符操作。

一对多关系的查询

我们在前面建立的Book表与Publish表就是一对多的关系:一本书只能有一个出版社,而同一个出版社可以出版多本书。
查询要点:正向查询按字段;反向查询按表名小写_set.all()。以Book表为基准,由于我们将关联的字段定义在了Book表中,也就是说“关联字段”在Book表中,所以从Book开始查是“正向”,从Publish开始查是“反向”。
这里列举一个正向查询的例子:查询主键为1的书籍的出版社的城市
book_obj = Book.objects.filter(pk=1).first()
ret = book_obj.publish.city
print(ret)
这里再列举一个反向查询的例子,大家可以类比的记忆,查询“苹果出版社”出版过的所有书籍的书名
publish_obj = Publish.objects.filter(name='苹果出版社').first()
book_list = publish.book_set.all()
for book_obj in book_list:
print(book_obj.title)

多对多关系查询:

我们在前面建立的Book表与Author表,就是“多对多”的关系。
查询要点:正向查询按字段;反向查询按表名小写_set.all()。以Book表为基准,由于我们将关联的字段定义在了Book表中,也就是说“关联字段”在Book表中,所以从Book开始查是“正向”,从Author开始查是“反向”。
这里还是列举一个正向查询的例子,“三国群英”所有的作者及手机号
book_obj = Book.objects.filter(title='三国群英').first()
authors = book_obj.authors.all()
for author_obj in authors:
name = author_obj.name
##手机号在“作者详细表”中,而且“作者表”相对于“作者详细表”是正向,关联字段为authordetail
telephone = author_obj.authordetail.telephone
print('作者:%s,手机号:%s'%(name,telephone))
下面是一个“反向查询”的例子,查询作者whw出版过的所有书籍的名字
author_obj = Author.objects.filter(name='whw').first()
book_list = author_obj.book_set.all()
for book_obj in book_list:
print(book_obj.title)

一对一关系的查询

Author表与AuthorDetail表是一对一的关系。
查询要点:正向查询按字段;反向查询按表名小写。以Author表为基准,由于我们将关联的字段定义在了Author表中,也就是说“关联字段”在Author表中,所以从Author开始查是“正向”,从AuthorDetail开始查是“反向”。
正向查询的例子,查询作者whw的电话
author = Author.objects.filter(name='whw').first()
##正向查询按字段
ret = author.authordetail.telephone
print(ret)
反向查询的例子:查询电话是12312312的作者名字
add = AuthorDetail.objects.filter(telephone=12312312).first()
#反向查询按表名小写:
print(add.author.name)

基于双下划线的跨表查询

基于双下划线的跨表查询————最终翻译成SQL语句都是“join查询” 。
这里直接给出查询规则——正向查询按字段,反向查询按表名小写——用来告诉ORM引擎join哪张表。其实本质上就是先join成一张表,再执行“单表查询”。这里还需要注意的一点是:查询中用到的APIvalues()等同于SQL语句中的select;filter()等同于SQL语句中的where。

一对多关系的双下划线查询

这里我们还是以BookPublish表为例。需要注意的是,正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表。
为了帮助大家更好的理解,下面的每个例子都与我们的SQL语句类比,帮助大家更容易的理解,因为基于双下滑先的跨表查询在实际中用的非常多!
例:查询水浒传这本书的出版社的名字
在SQL中我们是这样实现的:
select publish.name from book inner join publish
on book.publish_id = publish.nid
where book.title='水浒传'
正向查询:
ret = Book.objects.filter(title='水浒传').values('publish__name')
print(ret)
反向查询:
ret = Publish.objects.filter(book__title='水浒传').values('name')

print(ret)

多对多关系的双下划线查询

这里我们还是以BookAuthor表为例。需要注意的是,正向查询按字段,反向查询按表名小写用来告诉ORM引擎join哪张表。
这里的例子我们还是用SQL进行类比
例:查询三国群英这本书所有作者的名字
注意这里总共涉及三张表:BookAuthorbook_authors。但是第三张表我们是用Django在Book中与Author建立关联生成的表,也就是说:Book查Author是“正向查询”,Author查Book是“反向查询”。
SQL语句实现:
select author.name from book inner join book_authors
on book.nid = book_author.book_id
inner join author
on book_authors.author_id = author.nid
where book.title = "三国群英"
正向查询:
ret = Book.objects.filter(title='三国群英').values('authors__name')
print(ret)
反向查询:
ret = Author.objects.filter(book__title='三国群英').values('name')
print(ret)

一对一关系的双下划线查询

一对一的关系相对的很好理解,我们这里直接给出例子,查询whw的手机号
正向查询
ret = Author.objects.filter(name='whw').values('authordetail__telephone')
print(ret)
反向查询
ret = AuthorDetail.objects.filter(author__name='whw').values('telephone')
print(ret)

聚合查询

在做聚合查询之前我们需要先引入下列模块:
from django.db.models import Max,Min,Avg,Count
这里直接给出一个例子大家体会一下它的用法,真的很简单。
例:查询所有书籍的平均价格以及最高的价格
from django.db.models import Avg,Max
ret = Book.objects.all().aggregate(avg_price=Avg('price'),max_price=Max('price'))
print(ret)

F与Q查询

F查询

在上面所有的例子中,我们构造的过滤器都只是将字段值与某个常量做比较。如果我们要对两个字段的值做比较,那该怎么做呢?
Django 提供 F() 来做这样的比较。F() 的实例可以在查询中引用字段,来比较同一个model实例中两个不同字段的值。
我们在使用前应先引入:
from django.db.models import F
比如我们想查询content_num大于read_num的书籍的名字:
ret = Book.objects.filter(content_num__gt=F('read_num')).values('title')
print(ret)
我们还可以将每个书籍的价格加10元:
Book.objects.all().update(price=F('price')+10)

Q查询

filter() 等方法中的关键字参数查询都是一起进行“AND” 的。 如果我们需要执行更复杂的查询(例如OR语句),我们可以使用Q对象。
当然使用前必须引入:
from django.db.models import Q
这里直接给出三个例子:
1、查找书名以“三国”开头或者价格等于100的书籍名称
ret = Book.objects.filter(Q(title__startswith='三国')|Q(price=100)).values('title')
print(ret)
2、查找书名不以“三国”开头的书籍名称
ret = Book.objects.filter(~Q(title__startswith='三国')).values('title')
print(ret)
Q查询与键值对的关系:先写Q再写键值对,而且是“且”的关系:
ret = Book.objects.filter(~Q(title__startswith='三国'),title__startswith='水').values('title')
print(ret)

分组查询

分组查询的思想跟我们SQL中group by的思路是一模一样的,也就是说,我们先按照某个字段为数据进行分组,然后再进行进一步的查询。
ORM的分组查询包括:单表下的分组查询与多表下的分组查询。

单表下的分组查询

准备工作:我们新建一张员工表emp,包含的字段有——:id、name、age、salary、dep(部门名)、province(省份)。models.py文件的类这样写:
class Emp(models.Model):
name = models.CharField(max_length=32)
age = models.IntegerField()
salary = models.DecimalField(max_digits=8,decimal_places=2)
dep = models.CharField(max_length=32)
province = models.CharField(max_length=32)
单表下的分组查询语法:

单表模型.objects.values('group by的字段').annotate(聚合函数('统计字段'))

例:查询每一个部门的名称以及员工的平均薪水
from django.db.models import Avg
ret = Emp.objects.values('dep').annotate(Avg('salary'))
print(ret)
另外还需要注意的是:在单表分组下,按着主键进行分组是没有任何意义的!这与我们SQL中是一样的道理。

多表下的分组查询

单表下的分组查询语法:
每一个后表模型.objects.values('pk').annotate(聚合函数('关联表__统计字段')).values('表模型的所有字段以及统计字段')
注意以哪张表中的字段分组,哪一张表就是“后表”。
为了方便大家理解,下面的例子还是用SQL语句进行类比
例:查询每一个作者的名字以及出版过的书籍的最高价格
SQL:
select author.name,Max(book.price) from book inner join book_authors
on book.nid = book_authors.book_id
inner join author
on autohr.nid = book_authors.author_id
group by author.nid
annotate方法:注意主键可以用 pk 表示;Author找Book是“反向查询”按表名小写
ret = Author.objects.values('pk').annotate(max_price=Max('book__price')).values('name','max_price')
print(ret)

ORM的多表查询详述的更多相关文章

  1. Django的orm练习---多表查询

    Django的orm练习---多表查询 表关系如下 表结构 : from django.db import models # Create your models here. # 多对多-----&g ...

  2. 数据库开发-Django ORM的单表查询

    数据库开发-Django ORM的单表查询 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.查询集 1>.查询集相关概述 查询会返回结果的集,它是django.db.mod ...

  3. Django的orm操作之表查询二

    复习 单表查询 # 单表操作 # 增 # 方式1 user_obj=models.User.objects.create(**kwargs) # 之一create # 方式2 user_obj=mod ...

  4. Django ORM queryset object 解释(子查询和join连表查询的结果)

    #下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) --- ...

  5. Django ORM 操作 必知必会13条 单表查询

    ORM 操作 必知必会13条 import os # if __name__ == '__main__': # 当前文件下执行 os.environ.setdefault('DJANGO_SETTIN ...

  6. 57 ORM多表查询

    多表查询from django.db import models# Create your models here. class Author(models.Model): nid = models. ...

  7. 55-56 ORM多表查询

    多表查询: KEY   ====>  通过ORM引擎如何跨表: 正向查询按字段,反向查询按表名小写 模型的创建: from django.db import models # Create yo ...

  8. 连表查询都用Left Join吧 以Windows服务方式运行.NET Core程序 HTTP和HTTPS的区别 ASP.NET SignalR介绍 asp.net—WebApi跨域 asp.net—自定义轻量级ORM C#之23中设计模式

    连表查询都用Left Join吧   最近看同事的代码,SQL连表查询的时候很多时候用的是Inner Join,而我觉得对我们的业务而言,99.9%都应该使用Left Join(还有0.1%我不知道在 ...

  9. Python与数据库[2] -> 关系对象映射/ORM[5] -> 利用 sqlalchemy 实现关系表查询功能

    利用 sqlalchemy 实现关系表查询功能 下面的例子将完成一个通过关系表进行查询的功能,示例中的数据表均在MySQL中建立,建立过程可以使用 SQL 命令或编写 Python 适配器完成. 示例 ...

随机推荐

  1. es6中...是什么意思。

    1. var set = new Set([1, 2, 3, 4, 4,4,4,4,2,2,2]) set=[...set] 2. let [head, ...tail] = [1, 2, 3, 4] ...

  2. laravel5.2加载自定义的aliyun扩展包

    把文件夹加载进来 在 app.php里面注册 serviceprovider 在 app/filesystems.php 里面 加入相关的配置 把 cloud的值 改成对应的扩展 在.env文件里面完 ...

  3. Daily record-September

    September11. I feel much more reassured when I've been for a health check. 体检之后我感到放心多了.2. The diseas ...

  4. 洛谷 P3899 [谈笑风生]

    简化题意 m次询问,每次询问x的子树中,与x节点距离不超过y的节点的子树和.n,m≤300,000. 思路 按照dfs序排序,每次将一个点的答案塞到第depu的位置,这样得到一个前缀和,每次询问作减法 ...

  5. python3入门教程(二)操作数据库(一)

    概述 最近在准备写一个爬虫的练手项目,基本想法是把某新闻网站的内容分类爬取下来,保存至数据库,再通过接口对外输出(提供后台查询接口).那么问题就来了,python到底是怎么去操作数据库的呢?我们今天就 ...

  6. useradd语法

    在Linux中 useradd 命令用来创建或更新用户信息. useradd 命令属于比较难用的命令 (low level utility for adding users),所以 Debian 系的 ...

  7. Spring Boot 简单小Demo 转载!!!

    Spring Boot简介 接下来我们所有的Spring代码实例将会基于Spring Boot,因此我们先来了解一下Spring Boot这个大杀器. Spring早期使用XML配置的方式来配置Spr ...

  8. Dilated Convolutions 空洞卷积

    Dilated Convolutions,中文一般称为空洞卷积或者扩张卷积,是一种改进的图像卷积方法. 扩张卷积工作示意图如下: 图a是普通的卷积,感受野是3*3,相当于扩充dilation=0 图b ...

  9. python中序列化模块json和pickle

    json模块:json是第三方包,不是系统内置模块,以字符串序列 常用操作有: json.dumps() # 将变量序列化,即将功能性字符转化为字符串 例: >>> import j ...

  10. Semantic Compositionality through Recursive Matrix-Vector Spaces-paper

    Semantic Compositionality through Recursive Matrix-Vector Spaces 作者信息:Richard Socher Brody Huval Chr ...