SQLAlchemy技术文档(中文版)(中)

http://www.cnblogs.com/iwangzc/category/620910.html

10.建立联系(外键)

是时候考虑怎样映射和查询一个和Users表关联的第二张表了。假设我们系统的用户可以存储任意数量的email地址。我们需要定义一个新表AddressUser相关联。

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()函数:这个函数告诉ORMAddress类应该和User类连接起来,通过使用addresses.userrelationship()使用外键明确这两张表的关系。决定Adderess.user属性是多对一的。relationship()的子函数backref()提供表达反向关系的细节:relationship()对象的集合被User.address引用。多对一的反向关系总是一对多。更多的细节参考Basic RelRational Patterns

这两个互补关系:Address.userUser.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集合,可变集合类型,例如setdict,都可以用,但是默认的集合类型是list

jack = User(name=‘jack‘, fullname=‘Jack Bean‘, password=‘gjffdd‘)
jack.addresses
[]

现在可以直接在User对象中添加Address对象。只需要指定一个完整的列表:

jack.addresses = [Address(email_address=‘[email protected]‘),Address(email_address=‘[email protected]‘)]
当使用双向关系时,元素在一个类中被添加后便会自动在另一个类中添加。这种行为发生在Python的更改事件属性中而不是用SQL语句:
>>> jack.addresses[1]
<Address(email_address=‘[email protected]‘)>
>>> 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=‘[email protected]‘)>,
<Address(email_address=‘[email protected]‘)>]
当我们访问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==‘[email protected]‘).all():   
    print u
    print a
<User(name=‘jack‘,fullname=‘JackBean‘, password=‘gjffdd‘)>
<Address(email_address=‘[email protected]‘)>
用Query.join()方法会更加简单:
>>>session.query(User).join(Address).\
...
    filter(Address.email_address==‘[email protected]‘).\
...
    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==‘[email protected]‘).\
...
    filter(adalias2.email_address==‘[email protected]‘):
...
    print username, email1,
email2
jack
[email protected] [email protected]
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!= ‘[email protected]‘).\
...
     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=‘[email protected]‘)>

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相对,建议直接查看文档吧

待补充。。。

时间: 2024-10-05 09:52:00

SQLAlchemy技术文档(中文版)(中)的相关文章

常用控件产品官方文档/手册/API列表 c#控件文档API列表 asp.net控件产品技术文档中文版

.netCHARTING报表图表控件 文档帮助手册Ab3d.PowerToys 文档帮助手册Ab3d.Reader3ds 文档帮助手册ABViewer 文档帮助手册 (工程图纸文档管理系统)Active DJ Studio 文档帮助手册Active Sound Editor 文档帮助手册Active Sound Recorder 文档帮助手册ActivePatch 文档帮助手册 (程序自动升级控件)Animated Chart 文档帮助手册BB FlashBack 文档帮助手册BB FlashB

SQLAlchemy技术文档(中文版)(上)

1.版本检查 import sqlalchemy sqlalchemy.__version__ 2.连接 from sqlalchemy import create_engine engine = create_engine('sqlite:///:memory:',echo=True) echo参数为True时,会显示每条执行的SQL语句,可以关闭.create_engine()返回一个Engine的实例,并且它表示通过数据库语法处理细节的核心接口,在这种情况下,数据库语法将会被解释称Pyth

SQLAlchemy技术文档(中文版)-下

10.建立联系(外键) 是时候考虑怎样映射和查询一个和Users表关联的第二张表了.假设我们系统的用户可以存储任意数量的email地址.我们需要定义一个新表Address与User相关联. from sqlalchemyimport ForeignKey from sqlalchemy.orm import relationship, backref class Address(Base): __tablename__ = 'addresses' id= Column(Integer, prim

开发技术文档汇总

开发技术文档汇总:(持续更新) 1 Underscore 中文文档    github地址   英文文档 2 Express中文文档   github地址 3 Backbone中文文档 Backbone英文文档   github地址 4 Jquery中文文档(适合1.0--2,0) 5 Bootstrap中文 6 Less中文 7 NodeJs中文API 8 node.js相关的中文文档及教程 9 ECMAScript262中文兼容库 10 浏览器hacks 11 Rapheal中文   相关文

d3js技术文档

D3js技术文档 概述 D3 allows you to bind arbitrary data to a Document Object Model (DOM), and then apply data-driven transformations to the document. For example, you can use D3 to generate an HTML table from an array of numbers. Or, use the same data to cr

OCR识别技术文档识别怎么用

OCR识别技术文档识别的概括 我们常说的OCR.文字识别.OCR识别技术文档识别是指通过电子设备等将纸质上的文字识别出来,形成可编辑的文字. OCR识别技术文档识别的流程 随着扫描仪的普及与广泛应用,再加上摄像头迅速发展的手机等智能终端设备的应用,OCR识别技术文档识别软件越来越被应用于各种业务系统中. 常规的OCR文字识别处理的过程包括: 1.图像输入.预处理:二值化图片.噪声去除.倾斜较正: 2.版面分析:把页面分为横排文本.竖排文本.表格.图片等不同区域,帮助字符切割.识别OCR: 3.设

Xamarin技术文档------VS多平台开发

此技术业余时间研究,仅供大家学习参考,不涉及深入研究,有一定开发基础的人员,应该都能较快上手. 一.简介 Xamarin始创于2011年,旨在使移动开发变得难以置信地迅捷和简单.Xamarin的产品简化了针对多种平台的应用开发,包括iOS.Android.Windows Phone和Mac App.Xamarin由许多著名的开源社区开发者创立和参与,而且也是Mono项目的主导者--C#与.NET框架的开源.跨平台实现. 作为一个跨平台开发框架,Xamarin.Mobile有很多优点.在这一框架内

如何快速阅读并理解英文的技术文档

作为一名程序员,要实现我们的产品,首先需要选择一种或几种编程语言,其次是使用各种工具和第三方库. 而在这个过程中,就少不了对这些语言.工具和第三方库的下载和学习. 下载一般都非常简单,但是关于如何使用,相信大家都会有各种各样的学习方法. 但是不管通过什么方式,追根溯源都会来到官方文档. 那么问题就来了!目前来说,大部分的官方文档都是英文的,如何才能快速的理解并使用官方文档呢? 今天,把自己的学习方法拿出来,和大家一起分享一下,希望大家可以尽量少走一些弯路,尽快的找到bug的解决方法. 说起来很简

Boost.Asio技术文档

Christopher Kohlhoff Copyright ? 2003-2012 Christopher M. Kohlhoff 以Boost1.0的软件授权进行发布(见附带的LICENSE_1_0.txt文件或从http://www.boost.org/LICENSE_1_0.txt) Boost.Asio是用于网络和低层IO编程的跨平台C++库,为开发者提供了C++环境下稳定的异步模型. 综述 基本原理 应用程序与外界交互的方式有很多,可通过文件,网络,串口或控制台.例如在网络通信中,完