ORM的多表查询详述

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) 

原文地址:https://www.cnblogs.com/paulwhw/p/9420594.html

时间: 2024-11-08 14:30:40

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

django orm 关联表查询

django orm 关联表数据,即sql的多表查询 例如两个表: Apply表中定义了字段position为foreignkey指向job表的id字段, 1.通过job表查找子表apply的字段信息: job.objects.values( 'id', 'job_type', 'apply__date_created') 连接符为小写的子表tablename+双下线+子表字段名即:apply__date_created 表示寻找Apply表中的date_created字段 等价于后台的SQL:

ORM::联表查询

按顺序来一步一步走: 第一先建立好数据库:我的数据库是mysql数据库,数据库共分为以下几个表: users  用户表(刚开始的时候我用的是user表名,由于kohana有喜欢建立model时在后面加复数的习惯,但是估计 user这个名字已经被占用了,指定$_table_name="user"也不行) posts 帖子 数据库导出代码如下: -- phpMyAdmin SQL Dump -- version 3.4.10.1deb1 -- http://www.phpmyadmin.n

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

利用 sqlalchemy 实现关系表查询功能 下面的例子将完成一个通过关系表进行查询的功能,示例中的数据表均在MySQL中建立,建立过程可以使用 SQL 命令或编写 Python 适配器完成. 示例中用到的表主要有3张,一张personInfo个人信息表,一张account_store账号信息表,以及一张person_account_rel的个人信息与账号关系表. 示例中将会通过已知的人物年龄和id通过个人信息表查出个人姓名(仅为参考示例,请忽略怪异的查找逻辑 :) ),随后根据关系表得到的人

Django 【补充】ORM跨表查询补充

models.Book.objects.filter(**kwargs): querySet [obj1,obj2]models.Book.objects.filter(**kwargs).values(*args) : querySet [{},{},{}]models.Book.objects.filter(**kwargs).values_list(title) : querySet [(),(),()] 跨表查询总结: 1.创建表 class Book(models.Model): ti

ORM单表查询,跨表查询,分组查询

单表查询之下划线 models.Tb1.objects.filter(id__lt=10, id__gt=1) # 获取id大于1 且 小于10的值models.Tb1.objects.filter(id__in=[11, 22, 33]) # 获取id等于11.22.33的数据models.Tb1.objects.exclude(id__in=[11, 22, 33]) # not in models.Tb1.objects.filter(name__contains="ven")

ORM跨表查询

首先,在项目中添加我们要查询的模型,并插入数据 在django根目录下创建一个查询的py文件,供我们测试 ORM跨表查询可以分为基于  对象的查询(子查询)  和基于 queryset(双下划线__) 的查询 基于对象的查询(子查询) 一对多的查询 正向查询:在有关联字段的表向被关联的表查询 一对多的正向查询(正向查询按字段) 查询名为 python开天辟地 这本书的出版社的邮箱 book_obj = models.Book.objects.filter(title="python开天辟地&qu

python 之 Django框架(orm单表查询、orm多表查询、聚合查询、分组查询、F查询、 Q查询、事务、Django ORM执行原生SQL)

12.329 orm单表查询 import os if __name__ == '__main__': # 指定当前py脚本需要加载的Django项目配置信息 os.environ.setdefault("DJANGO_SETTINGS_MODULE", "orm_demo.settings") import django django.setup() # 启动Django项目 from app01 import models #返回QuerySet对象的方法: r

Django的ORM表查询

目录 Django的ORM表查询 单表查询 多表查询 聚合查询 分组查询 F与Q查询 Django的ORM表查询 先创建一个数据库,做前期准备 为了方便测试,不再进行urls对应关系和views的书写,直接测试的单个文件 那么如何只单独测试Django中的某个py文件,有以下方法 在任意一个py文件中书写以下代码 可以在应用app的目录下的tests.py中书写 也可以自己建立一个py文件书写 import os if __name__ == "__main__": os.enviro

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

#下面两种是基于QuerySet查询 也就是说SQL中用的jion连表的方式查询books = models.UserInfo.objects.all() print(type(books)) ---> <class 'django.db.models.query.QuerySet'> 查询出来是一个对象QuerySey 取值 print(books.values()) books = models.UserInfo.objects.filter()print(type(books))