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. 洛谷P3225 HNOI2012 矿场搭建

    题目描述 煤矿工地可以看成是由隧道连接挖煤点组成的无向图.为安全起见,希望在工地发生事故时所有挖煤点的工人都能有一条出路逃到救援出口处.于是矿主决定在某些挖煤点设立救援出口,使得无论哪一个挖煤点坍塌之 ...

  2. CF 3-6 2级组 D题 STRESSFUL TRAINING 紧张的比赛

    题目大概是这样的: 给出一个数列a[n] ,对于每一个数 a [i] 来说 都会在 T - - 时 -= b[i] 每个数都在任何时刻不能小于0 你可以在每次T - - 之前时给 一 个 a[i] + ...

  3. [luogu P3648] [APIO2014]序列分割

    [luogu P3648] [APIO2014]序列分割 题目描述 小H最近迷上了一个分隔序列的游戏.在这个游戏里,小H需要将一个长度为n的非负整数序列分割成k+1个非空的子序列.为了得到k+1个子序 ...

  4. erlang大法好

    可惜haxe不能生成erlang.不过没关系,s6k输入法的实际执行方案,现在由typescript改用haxe.cdt3的ts地位不变. 以后这个博客大部分内容都是跟haxe/typescript相 ...

  5. github的优势

    1.GitHub作为托管平台只支持git版本库托管而不像其他开源项目托管平台还对CVS.SVN.Hg 等格式的版本库进行托管.GitHub 的哲学很简单,既然 Git 是最好的版本控制系统之一(对于很 ...

  6. LeetCode 46 全排列

    题目: 给定一个没有重复数字的序列,返回其所有可能的全排列. 示例: 输入: [1,2,3] 输出: [ [1,2,3], [1,3,2], [2,1,3], [2,3,1], [3,1,2], [3 ...

  7. Android开发 ---Media

    1.ctivity_main.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout ...

  8. Matlab_audiowrite_音频生成

    输出音频文件所需函数为 audiowrite .通过例程进行解释: % 生成时间序列 fs = 5000; % [Hz] 信号采样频率 T = 1; % [s] 信号长度 x = 0:1/fs:T; ...

  9. SQL注入之Sqli-labs系列第三十三关(基于宽字符逃逸注入)

    开始挑战第三十三关(Bypass addslashes) 0x1查看源码 本关和第三十二关其实是一样的,只是这里用到了addslashes()函数 function check_addslashes( ...

  10. SQL注入之Sqli-labs系列第三十二关(基于宽字符逃逸注入)

    开始挑战第三十二关(Bypass addslashes) 0x1查看源代码 (1)代码关键点 很明显,代码中利用正则匹配将 [ /,'," ]这些三个符号都过滤掉了 function che ...