【SQLAlchemy】SQLAlchemy技术文档(中文版)(中)
10.建立联系(外键)
是时候考虑怎样映射和查询一个和Users表关联的第二张表了。假设我们系统的用户可以存储任意数量的email地址。我们需要定义一个新表Address与User相关联。
from sqlalchemyimport ForeignKey from sqlalchemy.ormimport relationship, backref
class Address(Base):
__tablename__ = 'addresses'
id= Column(Integer, primary_key=True)
email_address = Column(String, nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship("User", backref=backref('addresses',order_by=id))
def__repr__(self):
return"<Address(email_address='%s')>"%self.email_address
构造类和外键简单,就不过多赘述。主要说明以下relationship()函数:这个函数告诉ORM,Address类应该和User类连接起来,通过使用addresses.user。relationship()使用外键明确这两张表的关系。决定Adderess.user属性是多对一的。relationship()的子函数backref()提供表达反向关系的细节:relationship()对象的集合被User.address引用。多对一的反向关系总是一对多。更多的细节参考Basic RelRational Patterns。
这两个互补关系:Address.user和User.addresses被称为双向关系。这是SQLAlchemy ORM的一个非常关键的功能。更多关系backref的细节参见Linking Relationships with Backref。
假设声明的方法已经开始使用,relationship()中和其他类关联的参数可以通过strings指定。在上文的User类中,一旦所有映射成功,为了产生实际的参数,这些字符串会被当做Python的表达式。下面是一个在User类中创建双向联系的例子:
class User(Base):
addresses = relationship("Address", order_by="Address.id", backref="user")
一些知识:
在大多数的外键约束(尽管不是所有的)关系数据库只能链接到一个主键列,或具有唯一约束的列。
外键约束如果是指向多个列的主键,并且它本身也具有多列,这种被称为“复合外键”。
外键列可以自动更新自己来相应它所引用的行或者列。这被称为级联,是一种建立在关系数据库的功能。
外键可以参考自己的表格。这种被称为“自引”外键。
我们需要在数据库中创建一个addresses表,所以我们会创建另一个元数据,这将会跳过已经创建的表。
11.操作主外键关联的对象
现在我们已经在User类中创建了一个空的addresser集合,可变集合类型,例如set和dict,都可以用,但是默认的集合类型是list。
jack = User(name='jack', fullname='Jack Bean', password='gjffdd')
jack.addresses
[]
现在可以直接在User对象中添加Address对象。只需要指定一个完整的列表:
jack.addresses = [Address(email_address='jack@google.com'),Address(email_address='j25@yahoo.com')]
当使用双向关系时,元素在一个类中被添加后便会自动在另一个类中添加。这种行为发生在Python的更改事件属性中而不是用SQL语句:
>>> jack.addresses[1]
<Address(email_address='j25@yahoo.com')>
>>> jack.addresses[1].user
<User(name='jack', fullname='Jack Bean', password='gjffdd')>
把jack提交到数据库中,再次查询Jack,(No SQL is yet issued for Jack’s addresses:)这句实在是翻译不了了,看看代码就明白是什么意思:
>>> jack = session.query(User).\
...
filter_by(name='jack').one()
>>> jack
<User(name='jack',fullname='Jack Bean', password='gjffdd')>
>>>jack.addresses
[<Address(email_address='jack@google.com')>,
<Address(email_address='j25@yahoo.com')>]
当我们访问uaddresses集合时,SQL会被突然执行,这是一个延迟加载(lazy loading)关系的典型例子。现在addresses集合加载完成并且可以像对待普通列表一样对其进行操作。以后我们会优化这种加载方式。
12.使用JOINS查询
现在我们有了两张表,可以进行更多的查询操作,特别是怎样对两张表同时进行查询,Wikipediapage on SQL JOIN提供了很详细的说明,其中一些我们将在这里说明。之前用Query.filter()时,我们已经用过JOIN了,filter是一种简单的隐式join:
>>>for u, a in session.query(User, Address).filter(User.id==Address.user_id).filter(Address.email_address=='jack@google.com').all():
print u
print a
<User(name='jack',fullname='JackBean', password='gjffdd')>
<Address(email_address='jack@google.com')>
用Query.join()方法会更加简单:
>>>session.query(User).join(Address).\
...
filter(Address.email_address=='jack@google.com').\
...
all()
[<User(name='jack',fullname='JackBean', password='gjffdd')>]
之所以Query.join()知道怎么join两张表是因为它们之间只有一个外键。如果两张表中没有外键或者有一个以上的外键,当下列几种形式使用的时候,Query.join()可以表现的更好:
query.join(Address,User.id==Address.user_id)# 明确的条件
query.join(User.addresses)# 指定从左到右的关系
query.join(Address,User.addresses) #同样,有明确的目标
query.join('addresses') # 同样,使用字符串
outerjoin()和join()用法相同
query.outerjoin(User.addresses)# LEFT OUTER JOIN
12.1使用别名
当在多个表中查询时,如果同一张表需要被引用好几次,SQL通常要求对这个表起一个别名,因此,SQL可以区分对这个表进行的其他操作。Query也支持别名的操作。下面我们joinAddress实体两次,找到同时拥有两个不同email的用户:
>>>from sqlalchemy.ormimport aliased
>>>adalias1 = aliased(Address)
>>>adalias2 = aliased(Address)
>>>for username, email1, email2 in\
...
session.query(User.name,adalias1.email_address,adalias2.email_address).\
...
join(adalias1, User.addresses).\
...
join(adalias2, User.addresses).\
...
filter(adalias1.email_address=='jack@google.com').\
...
filter(adalias2.email_address=='j25@yahoo.com'):
...
print username, email1,
email2
jack
jack@google.com j25@yahoo.com
12.1使用子查询(暂时理解不了啊,多看代码研究吧:()
from sqlalchemy.sqlimport func
stmt = session.query(Address.user_id,func.count('*').\
...
label('address_count')).\
...
group_by(Address.user_id).subquery()
>>>
for u, count in session.query(User,stmt.c.address_count).\
...
outerjoin(stmt, User.id==stmt.c.user_id).order_by(User.id):
print u, count
<User(name='ed',fullname='EdJones', password='f8s7ccs')>
None
<User(name='wendy',fullname='Wendy Williams', password='foobar')>
None
<User(name='mary',fullname='Mary Contrary', password='xxg527')>
None
<User(name='fred',fullname='Fred Flinstone', password='blah')>
None
<User(name='jack',fullname='Jack Bean', password='gjffdd')>
2
12.2从子查询中选择实体?
上面的代码中我们只返回了包含子查询的一个列的结果。如果想要子查询映射到一个实体的话,使用aliased()设置一个要映射类的子查询别名:
>>>
stmt = session.query(Address).\
...
filter(Address.email_address!= 'j25@yahoo.com').\
...
subquery()
>>>
adalias = aliased(Address, stmt)
#?为什么有两个参数?
>>>
for user, address in session.query(User, adalias).\
...
join(adalias, User.addresses):
...
print user
...
print address
<User(name='jack',fullname='Jack Bean', password='gjffdd')>
<Address(email_address='jack@google.com')>
12.3使用EXISTS(存在?)
如果表达式返回任何行,EXISTS为真,这是一个布尔值。它可以用在jions中,也可以用来定位在一个关系表中没有相应行的情况:
>>>from sqlalchemy.sqlimport exists
>>>
stmt = exists().where(Address.user_id==User.id)
>>>for name, in session.query(User.name).filter(stmt):
print name
jack
等价于:
>>>for name, in session.query(User.name).\
...
filter(User.addresses.any()):
...
print name
jack
any()限制行匹配:
>>>for name, in session.query(User.name).\
... filter(User.addresses.any(Address.email_address.like('%google%'))):
...
print name
jack
has()和any()一样在应对多对一关系的情况下(注意“~“意味着”NOT”)
>>> session.query(Address).\
...
filter(~Address.user.has(User.name=='jack')).all()
[]
12.4 常见的关系运算符
== != None 都是用在多对一中,而contains()用在一对多的集合中:
query.filter(Address.user == someuser)
query.filter(User.addresses.contains(someaddress))
Any()(用于集合中):
query.filter(User.addresses.any(Address.email_address == 'bar'))#also takes keyword arguments:
query.filter(User.addresses.any(email_address='bar'))
as()(用在标量?不在集合中):
query.filter(Address.user.has(name='ed'))
Query.with_parent()(所有关系都适用):
session.query(Address).with_parent(someuser,'addresses')
13 预先加载(跟性能有关)和lazy loading相对,建议直接查看文档吧
待补充。。。
原文:http://www.cnblogs.com/iwangzc/p/4114913.html
【SQLAlchemy】SQLAlchemy技术文档(中文版)(中)的更多相关文章
- 常用控件产品官方文档/手册/API列表 c#控件文档API列表 asp.net控件产品技术文档中文版
.netCHARTING报表图表控件 文档帮助手册Ab3d.PowerToys 文档帮助手册Ab3d.Reader3ds 文档帮助手册ABViewer 文档帮助手册 (工程图纸文档管理系统)Activ ...
- 用python把技术文档中,每个模块系列截图生成一个动态GIF
前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 最近在写技术文档的时候,发现一个问题.对于每个技术步骤,都需要一个截图,这 ...
- Kafka 技术文档
Kafka 技术文档 目录 1 Kafka创建背景 2 Kafka简介 3 Kafka好处 3.1 解耦 3.2 冗余 3.3 扩展性 3.4 灵活性 & 峰值处理能力 3.5 可恢复性 ...
- RabbitMq 技术文档
RabbitMq 技术文档 目录 1 AMQP简介 2 AMQP的实现 3 RabbitMQ简介 3.1 概念说明 3.2 消息队列的使用过程 3.3 RabbitMQ的特性 4 RabbitMQ使用 ...
- [转]unity3d 脚本参考-技术文档
unity3d 脚本参考-技术文档 核心提示:一.脚本概览这是一个关于Unity内部脚本如何工作的简单概览.Unity内部的脚本,是通过附加自定义脚本对象到游戏物体组成的.在脚本对象内部不同志的函数被 ...
- [转]chrome技术文档列表
chrome窗口焦点管理系统 http://www.douban.com/note/32607279/ chrome之TabContents http://www.douban.com/note/32 ...
- 使用Jupyter Notebook编写技术文档
1.jupyter Notebook的组成 这里它的组件及其工程构成,帮助大家更好的用好jupyter Notebook 组件 Jupyter Notebook结合了三个组件: 笔记本Web应用程序: ...
- 技术文档生成工具:appledoc
做项目一般都会要求写技术文档,特别是提供SDK或者基础组件的.如果手写这类技术文档的话,工作量比编写代码也少不了多少.比如 Java 语言本身就自带 javadoc 命令,可以从源码中抽取文档.本篇我 ...
- d3js技术文档
D3js技术文档 概述 D3 allows you to bind arbitrary data to a Document Object Model (DOM), and then apply ...
- 程序员如何编写好开发技术文档 如何编写优质的API文档工作
编写技术文档,是令众多开发者望而生畏的任务之一.它本身是一件费时费力才能做好的工作.可是大多数时候,人们却总是想抄抄捷径,这样做的结果往往非常令人遗憾的,因为优质的技术文档是决定你的项目是否引人关注的 ...
随机推荐
- ABAP术语-ABAP Workbench
ABAP Workbench 原文:http://www.cnblogs.com/qiangsheng/archive/2007/12/10/989037.html Integrated graphi ...
- springboot中有用的几个有用aware以及bean操作和数据源操作
本文参考了: https://blog.csdn.net/derrantcm/article/details/76652951 https://blog.csdn.net/derrantcm/arti ...
- Keras模型的保存方式
Keras模型的保存方式 在运行并且训练出一个模型后获得了模型的结构与许多参数,为了防止再次训练以及需要更好地去使用,我们需要保存当前状态 基本保存方式 h5 # 此处假设model为一个已经训练好的 ...
- js面试之一个字符串中出现次数最多的字符是?出现几次?
最近在找面试题的时候发现了许多有趣的题目,在这里用随笔记录下~ 关于“一个字符串中出现次数最多的字符...”这种问题在笔试题中出现的频率还是很高的,我自己也找到了几种方法处理 var str = &q ...
- 在Vue项目里面使用d3.js
之前写一个 Demo里面 有些东西要使用d3实现一些效果 但是在很多论坛找资源都找不到可以在Vue里面使用D3.js的方法,npm 上面的D3相对来说 可以说是很不人性化了 完全没有说 在webpac ...
- 微信小程序引用iconfont图标字体解决方案;
1)首先,登录阿里巴巴iconfont.cn 2)新建项目 3)点击icon收藏 4)加入到test项目中 5)下载到本地解压 6)生成代码 7)复制iconfont.css到xxx.wx ...
- PHP接收http请求头信息
1.PHP 自带函数 getallheaders() 目前 getallheaders() 只能用于 apache 中.如果想在 nginx 中也能使用,可以使用自定义函数. foreach (get ...
- Delphi方法重载
unit Unit1; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms ...
- LeetCode 二叉树的层次遍历 C++
给定一个二叉树,返回其按层次遍历的节点值. (即逐层地,从左到右访问所有节点). 例如:给定二叉树: [3,9,20,null,null,15,7], 3 / \ 9 20 / \ 15 7 返回其层 ...
- python2.7练习小例子(二十九)
29):1.题目:按相反的顺序输出列表的值. #!/usr/bin/python # -*- coding: UTF-8 -*- a = ['one', 'two', 'three'] for ...