SQLAlchemy使用笔记--SQLAlchemy ORM(二)
參考:
http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html#building-a-relationship
http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html#working-with-related-objects
建立表之间带关系
建立外建
在address加入user的外键
from sqlalchemy import ForeignKey, Column, String, Integer
from sqlalchemy.orm import relationship
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
password = Column(String)
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))
relationship中的backref參数使用形式:
backref="addresses" #直接使用表名的字符串
backref=backref('addresses') #使用backref函数
backref=backref('addresses', order_by=id)) #brackref函数能够加入參数,详见http://docs.sqlalchemy.org/en/rel_1_0/orm/backref.html#backref-arguments
能够使用user.addresses 从user获取address 和,使用address.users 虫address获取user
backref 会在User跟Address上都加上关系,它本质是:
from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String)
addresses = relationship("Address", back_populates="user")
class Address(Base):
__tablename__ = 'address'
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer, ForeignKey('user.id'))
user = relationship("User", back_populates="addresses")
relationship中的
加入
>>> jack.addresses = [
... Address(email_address='jack@google.com'),
... Address(email_address='j25@yahoo.com')]
获取
>>> jack.addresses[1]
<Address(email_address='j25@yahoo.com')>
>>> jack.addresses[1].user
<User(name='jack', fullname='Jack Bean', password='gjffdd')>
commit
session.add(jack)
session.commit()
address 会自己主动的加入
one to many 关系
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
children = relationship("Child", backref="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
many to one 关系
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child", backref="parents")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
one to one 关系
from sqlalchemy.orm import backref
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
child = relationship("Child", backref=backref("parent", uselist=False))
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
many to many 关系
须要一个中间表和在relatonship 加入secondary參数
association_table = Table('association', Base.metadata,
Column('left_id', Integer, ForeignKey('left.id')),
Column('right_id', Integer, ForeignKey('right.id'))
)
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Child",
secondary=association_table,
backref="parents")
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
这样在child加入删除parent或者parent加入删除child时,无需对中间表进行操作。直接加入删除就可以。
parent.children.append(child)
child.parents.append(parent)
也能够 使用类来创建中间表,这样能够在中间表中保存一些其它的信息。可是就不能想前面一样自己主动对中间表进行操作。
class Association(Base):
__tablename__ = 'association'
left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
extra_data = Column(String(50))
child = relationship("Child", back_populates="parents")
parent = relationship("Parent", back_populates="children")
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
children = relationship("Association", back_populates="parent")
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
parents = relationship("Association", back_populates="child")
join 操作
能够使用Query.join()
>>> session.query(User).join(Address).\
... filter(Address.email_address=='jack@google.com').\
... all()
[<User(name='jack', fullname='Jack Bean', password='gjffdd')>]
在User上能够直接使用join(Address) 由于仅仅有一个外建在User和Address之间,其它join形式:
query.join(Address, User.id==Address.user_id) # explicit condition
query.join(User.addresses) # specify relationship from left to right
query.join(Address, User.addresses) # same, with explicit target
query.join('addresses') # same, using a string
使用外链接
query.outerjoin(User.addresses) # 默认是左外连接。
当query中有多个实体点使用,使用join默认join追左边的那个,
比如:
query = session.query(User, Address).join(User) # 报错
query = session.query(Address, User).join(User) # 正确
假设想自定使用join那个表。能够使用select_form
query = Session.query(User, Address).select_from(Address).join(User)
alias 别名
假设想join自己,能够使用别名
from sqlalchemy.orm import 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)
使用子查询
直接看官方文档的样例:
>>> from sqlalchemy.sql import 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='Ed Jones', 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
使用EXISTS
看官方文档的样例:
>>> from sqlalchemy.sql import exists
>>> stmt = exists().where(Address.user_id==User.id)
SQL>>> 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
user.addresses 能够像user中其它属性一样在filter使用==、!=、any等等。
query.filter(Address.user == someuser)
query.filter(Address.user != someuser)
query.filter(Address.user == None)
query.filter(User.addresses.contains(someaddress))
query.filter(User.addresses.any(Address.email_address == 'bar'))# also takes keyword arguments:
query.filter(User.addresses.any(email_address='bar'))
query.filter(Address.user.has(name='ed'))
session.query(Address).with_parent(someuser, 'addresses')
SQLAlchemy使用笔记--SQLAlchemy ORM(二)的更多相关文章
- SQLAlchemy 学习笔记(二):ORM
照例先看层次图 一.声明映射关系 使用 ORM 时,我们首先需要定义要操作的表(通过 Table),然后再定义该表对应的 Python class,并声明两者之间的映射关系(通过 Mapper). 方 ...
- SQLAlchemy 学习笔记(三):ORM 中的关系构建
个人笔记,不保证正确. 关系构建:ForeignKey 与 relationship 关系构建的重点,在于搞清楚这两个函数的用法.ForeignKey 的用法已经在 SQL表达式语言 - 表定义中的约 ...
- SQLAlchemy使用笔记--SQLAlchemy ORM(三)
參考: http://docs.sqlalchemy.org/en/rel_1_0/orm/tutorial.html#eager-loading 预先载入 前面的代码,由于是lazy load.当我 ...
- SQLAlchemy 学习笔记(一):Engine 与 SQL 表达式语言
个人笔记,如有错误烦请指正. SQLAlchemy 是一个用 Python 实现的 ORM (Object Relational Mapping)框架,它由多个组件构成,这些组件可以单独使用,也能独立 ...
- Sqlalchemy python经典第三方orm
Ⅰ. 安装 pip install sqlalchemy Ⅱ. 起步链接 import time import threading import sqlalchemy from sqlalchemy ...
- Django和SQLAlchemy,哪个Python ORM更好?
ORM是什么? 在介绍Python下的两个ORM框架(Django和SQLAlchemy)的区别之前,我们首先要充分了解ORM框架的用途. ORM代表对象关系映射.ORM中的每个单词解释了他们在实际项 ...
- SQLAlchemy 简单笔记
ORM 江湖##### 曾几何时,程序员因为惧怕SQL而在开发的时候小心翼翼的写着sql,心中总是少不了恐慌,万一不小心sql语句出错,搞坏了数据库怎么办?又或者为了获取一些数据,什么内外左右连接,函 ...
- Python与数据库[2] -> 关系对象映射/ORM[3] -> sqlalchemy 的声明层 ORM 访问方式
sqlalchemy的声明层ORM访问方式 sqlalchemy中可以利用声明层进行表格类的建立,并利用ORM对象进行数据库的操作及访问,另一种方式为显式的 ORM 访问方式. 主要的建立步骤包括: ...
- Python与数据库[2] -> 关系对象映射/ORM[4] -> sqlalchemy 的显式 ORM 访问方式
sqlalchemy 的显式 ORM 访问方式 对于sqlalchemy,可以利用一种显式的ORM方式进行访问,这种方式无需依赖声明层,而是显式地进行操作.还有一种访问方式为声明层 ORM 访问方式. ...
随机推荐
- tomcat修改内存
windows: 修改bin/catalina.bat, 第一行添加 set JAVA_OPTS=-Xms256m -Xmx512m linux: 修改bin/catalina.sh 第一行添加 JA ...
- springboot的mvn与gradle启动方式
1 很简单,直接鼠标右击项目,run启动项目 2 项目目录下的命令行 mvn spring-boot:run 或者 gradlew bootRun 3 进入libs下或者target下 java ...
- Spring注解@Scope("prototype")
spring 默认scope 是单例模式 这样只会创建一个Action对象 每次访问都是同一个Action对象,数据不安全 struts2 是要求 每次次访问 都对应不同的Action scope=& ...
- 使用 ceph 作为 openstack 的后端
openstack 与 ceph 集成 在 ceph 上创建 openstack 需要的 pool. sudo ceph osd pool create volumes 128 sudo ceph o ...
- 洛谷 P3919 【模板】可持久化数组(可持久化线段树/平衡树)-可持久化线段树(单点更新,单点查询)
P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目背景 UPDATE : 最后一个点时间空间已经放大 标题即题意 有了可持久化数组,便可以实现很多衍生的可持久化功能(例如:可持久化并查集 ...
- sql查询总结
1.SQL select 语句 SELECT 语句用于从表中选取数据. 结果被存储在一个结果表中(称为结果集). SELECT 列名称 FROM 表名称 实例: SELECT username,pas ...
- 两个线程交替打印奇偶数【Lock版】
import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public clas ...
- ProgrammingProjectList-文本操作
https://github.com/jobbole/ProgrammingProjectList 逆转字符串——输入一个字符串,将其逆转并输出. package com.zrl.github; im ...
- 洛谷P1730最小密度路径
题目传送门; 首先理解题目,究其本质就是一个最短路问题,而且数据范围贼水,用floyd完全没问题,但是题目有变化,要求出路径边权值与边数之比,这里就可以考虑在把floyd中的二维数组变为三维,f[ i ...
- Oracle unique / distinct
[唯一]DISTINCT与UNIQUE的“区别” 今天一个朋友在Oracle中偶然发现UNIQUE也可以得到唯一的数据结果,问到DISTINCT与UNIQUE的区别.答案是:他们没有区别! d ...