- 版本检查
import sqlalchemy
print(sqlalchemy.__version__)
print(dir(sqlalchemy))
- 连接
- 示例
sqlite3_engine = sqlalchemy.create_engine('sqlite:///:memory', echo=True, encoding='UTF-8')
print(dir(sqlite3_engine))
- postgresql
engine = create_engine('postgresql://scott:tiger@localhost/mydatabase')
engine = create_engine('postgresql+psycopg2://scott:tiger@localhost/mydatabase')
engine = create_engine('postgresql+pg8000://scott:tiger@localhost/mydatabase')
- mysql
engine = create_engine('mysql://scott:tiger@localhost/foo')
engine = create_engine('mysql+mysqldb://scott:tiger@localhost/foo')
engine = create_engine('mysql+pymysql://scott:tiger@localhost/foo')
- oracle
engine = create_engine('oracle://scott:tiger@127.0.0.1:1521/sidname')
engine = create_engine('oracle+cx_oracle://scott:tiger@tnsname')
- microsoft sql server
engine = create_engine('mssql+pyodbc://scott:tiger@mydsn')
engine = create_engine('mssql+pymssql://scott:tiger@hostname:port/dbname')
- sqlite
engine = create_engine('sqlite:///foo.db')
engine = create_engine('sqlite:absolute/path/to/foo.db')
engine = create_engine('sqlite:///C:\\path\\to\\foo.db')
engine = create_engine(r'sqlite:///C:\path\to\foo.db')
engine = create_engine('sqlite://')
- sqlalchemy.engine_from_config(configuration, prefix=‘sqlalchemy.’, **kwargs)
- sqlalchemy.engine.url.make_url(name_or_url) # class sqlalchemy.engine.url.URL(drivername, username=None, password=None, host=None, port=None, database=None, query=None)
- url.get_dialect()
- url.translate_connect_args(names=[], **kw)
- 建表
from sqlalchemy import Table, Column, Integer, String, MetaData, ForeignKey
metadata = MetaData()
users = Table('users', metadata, Column('id', Integer, primary_key=True), Column('name', String), Column('fullname', String))
addresses = Table('addresses', metadata, Column('id', Integer, primary_key=True), Column('user_id', None, ForeignKey('users.id')), Column('email_address', String, nullable=True))
metadata.create_all(sqlite3_engine)
print(dir(users))
- 插入
ins = users.insert()
print(ins)
ins = users.insert().values(name='jack', fullname='Jack Jones')
print(ins)
print(ins.compile().params)
- 执行
conn = sqlite3_engine.connect()
result = conn.execute(ins)
ins.bind = engine
print(ins)
print(result.inserted_primary_key)
- 执行多条语句
ins = users.insert()
result = conn.execute(ins, id=2, name='wendy', fullname='Wendy Williams')
results = conn.execute(addresses.insert(), [
{'user_id': 1, 'email_address': 'jack@yahoo.com'}
{'user_id': 1, 'email_address': 'jack@msn.com'}
{'user_id': 2, 'email_address': 'www@www.org'}
{'user_id': 2, 'email_address': 'wendy@aol.com'}
])
- 查询
from sqlalchemy.sql import select
sel = select([users])
result = conn.execute(sel)
for row in result:
print(row)
result.close()
result = conn.execute(sel)
row = result.fetchone()
print("name:", row['name'], "; fullname:", row['fullname'])
print("name:", row[1], "; fullname:", row[2])
print("name:", row[users.c.name], "; fullname:", row[users.c.fullname])
result.close()
for row in conn.execute(select([users, addresses])):
print(row)
s = select([users, addresses]).where(users.c.id == addresses.c.user_id)
for row in conn.execute(s):
print(row)
- Operators https://docs.sqlalchemy.org/en/13/core/tutorial.html#operators
print(users.c.id == addresses.c.user_id)
print(users.c.id == 7)
print((users.c.id == 7).compile().params)
print(users.c.id != 7)
print(users.c.name == None)
print('fred' > users.c.name)
print(users.c.id + addresses.c.id)
print(users.c.name + users.c.fullname)
print((users.c.name + users.c.fullname).compile(bind=create_engine('mysql://')))
print(users.c.name.op('tiddlywinks')('foo'))
print(somecolumn.op('&')(0xff))
from sqlalchemy import type_coerce
expr = type_coerce(somecolumn.op('-%>')('foo'), MySpecialType())
stmt = select([expr])
somecolumn.bool_op('-->')('some value')
- 连接
from sqlalchemy.sql import and_, or_, not_
print(and_(
users.c.name.like('j%'),
users.c.id == addresses.c.user_id,
or_(
addresses.c.email_address == 'wendy@aol.com',
addresses.c.email_address == 'jack@yahoo.com'
),
not_(users.c.id > 5)
))
print(users.c.name.like('j%') & (users.c.id == addresses.c.user_id) & ((addresses.c.email_address == 'wendy@aol.com') | (addresses.c.email_address == 'jack@yahoo.com')) & ~(users.c.id>5))
s = select(
[(users.c.fullname + ', ' + addresses.c.email_address).label('title')]. \
where(and_(
users.c.id == addresses.c.user_id,
users.c.name.between('m', 'z'),
or_(
addresses.c.email_address.like('%@aol.com'),
addresses.c.email_address.like('%@msn.com')
))))
rows = conn.execute(s).fetchall()
s = select(
[(users.c.fullname + ', ' + addresses.c.email_address).label('title')]. \
where(users.c.id == addresses.c.user_id). \
where(users.c.name.between('m', 'z')). \
where(or_(
addresses.c.email_address.like('%@aol.com'),
addresses.c.email_address.like('%@msn.com')
)))
- textual sql https://docs.sqlalchemy.org/en/13/core/tutorial.html#using-textual-sql
from sqlalchemy.sql import text
s = text('select concat(users.fullname, ", ", addresses.email_address) as title from users, addresses where users.id=addresses.user_id and users.name between :x and :y and (addresses.email_address like :e1 or addresses.email_address like :e2)')
conn.execute(s, x='m', y='z', e1='%@aol.com', e2='%@msn.com').fetchall()
s = text("select * from users where users.name between :x and :y")
s = s.bindparmas(x='m', y='z'); conn.execute(s)
s = s..bindparams(bindparam("x", type_=String), bindparam("y", type_=String)); conn.execute(s, {'x': 'm', 'y': 'z'})
s = s.columns(id=Integer, name=String)
s = text("select name, id from users"); s = s.columns(users.c.id, users.c.name)
- …
- API
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, func, ForeignKey, exists
from sqlalchemy.orm import sessionmaker, aliased, relationship
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
print(User.__table__)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
session.add(User(name='ed', fullname='Ed Jones', nickname='edsnickname'))
session.add_all([
User(name='wendy', fullname='Wendy Williams', nickname='windy'),
User(name='mary', fullname='Mary Contrary', nickname='mary'),
User(name='fred', fullname='Fred Flintstone', nickname='freddy')
])
our_user = session.query(User).filter_by(name='ed').first()
query = session.query(User).filter(User.name.in_(['Edwardo', 'fakeuser']))
for row in session.query(User).order_by(User.id):
print(row.name, row.fullname)
for name, fullname in session.query(User.name, User.fullname):
print(name, fullname)
for row in session.query(User, User.name, User.name.label('name_label')).all():
print(row.User, row.name, row.name_label)
user_alias = aliased(User, name='user_alias')
for row in session.query(user_alias, user_alias.name).all():
print(row.user_alias)
query.all()
query.first()
query.one()
query.one_or_none()
query.scalar()
query.count()
session.query(func.count(User.name), User.name).group_by(User.name).all()
session.query(func.count('*')).select_from(User).scalar()
session.query(func.count(User.id)).scalar()
our_user.nickname = 'eddie'
print(session.dirty)
print(session.new)
session.commit()
session.rollback()
fake_user in session
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email_address = Column(String(50), nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship('User', back_populates='addresses')
def __repr__(self):
return '<Address(email_address="%s")>' % self.email_address
User.addresses = relationship('Address', order_by=Address.id, back_populates='users')
Base.metadata.create_all(engine)
query.join(Address).filter(...)
query.outerjoin(User.addresses).filter(...)
stmt = session.query(Address.user_id, func.count('*').label('address_count')).group_by(Address.user_id).subquery()
result = session.query(User, stmt.c.address_count).outerjoin(stmt, User.id==stmt.c.user_id).order_by(User.id)
- 创建映射和表
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, CHAR, VARCHAR, Enum, TIMESTAMP
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
test1 = Column(CHAR(20))
test2 = Column(VARCHAR(20))
test3 = Column('test3', Enum('item1', 'item2'))
test4 = Column('test4', TIMESTAMP)
def __repr__(self):
return "<User(name='%s', fullname='%s', nickname='%s')>" % (self.name, self.fullname, self.nickname)
print(User.__table__)
Base.metadata.create_all(engine)
- 创建实例
ed_user = User(name='ed', fullname='Ed Jones', nickname='edsnickname')
print(ed_user.name, ed_user.fullname, ed_user.nickname, ed_user.id)
- 创建会话
from sqlalchemy.orm import sessionmaker
Session = sessionmaker(bind=engine)
session = Session()
- 添加和更新对象
session.add(ed_user)
our_user = session.query(User).filter_by(name='ed').first()
print(ed_user is our_user)
session.add_all([
User(name='wendy', fullname='Wendy Williams', nickname='windy'),
User(name='mary', fullname='Mary Contrary', nickname='mary'),
User(name='fred', fullname='Fred Flintstone', nickname='freddy')
])
ed_user.nickname = 'eddie'
print(session.dirty)
print(session.new)
session.commit()
- 回滚
ed_user.name = 'Edwardo'
fake_user = User(name='fakeuser', fullname='Invalid', nickname='12345')
session.add(fake_user)
session.query(User).filter(User.name.in_(['Edwardo', 'fakeuser'])).all()
session.rollback()
ed_user.name
fake_user in session
session.query(User).filter(User.name.in_(['ed', 'fakeuser'])).all()
- 查询
- 基础查询
for instance in session.query(User).order_by(User.id):
print(instance.name, instance.fullname)
for name, fullname in session.query(User.name, User.fullname):
print(name, fullname)
for row in session.query(User, User.name, User.name.label('name_label')).all():
print(row.User, row.name, row.name_label)
from sqlalchemy.orm import aliased
user_alias = aliased(User, name='user_alias')
for row in session.query(user_alias, user_alias.name).all():
print(row.user_alias)
for name, in session.query(User.name).filter_by(fullname='Ed Jones'): pass
for name, in session.query(User.name).filter(User.fillname=='Ed Jones'): pass
- filter()方法常用语句
query.filter(User.name == 'ed')
query.filter(User.name != 'ed')
query.filter(User.name.like('%ed%'))
query.filter(User.name.ilike('%ed%'))
query.filter(User.name.in_(['ed', 'wendy', 'jack']))
query.filter(User.name.in_(session.query(User.name).filter(User.name.like('%ed%'))))
query.filter(~User.name.in_(['ed', 'wendy', 'jack']))
query.filter(User.name == None)
query.filter(User.name != None)
from sqlalchemy import and_, or_, not_
query.filter(and_(User.name == 'ed', User.fullname == 'Ed Jones'))
query.filter(or_(User.name == 'ed', User.fullname == 'Ed Jones'))
query.filter(User.name.match('wendy'))
- 返回
query = session.query(User).filter(User.name.like('%ed')).order_by(User.id)
query.all()
query.first()
query.one()
query.one_or_none()
query.scalar()
- 使用文本sql
from sqlalchemy import text
for user in session.query(User).filter(text('id < 224')).order_by(text('id')).all():
print(user)
session.query(User).filter(text('id < :value and name = :name')).params(value=224, name='fred').order_by(User.id).one()
session.query(User).from_statement(text('select * from users where name = :name')).parmas(name='ed').all()
stmt = text('select name, id, fullname, nickname from users where name = :name')
stmt = stmt.columns(User.name, User.id, User.fullname, User.nickname)
session.query(User).from_statement(stmt).params(name='ed').all()
stmt = text('select name, id from users where name = :name')
stmt = stmt.columns(User.name, User.id)
session.query(User.id, User.name).from_statement(stmt).params(name='ed').all()
- 计数
query.count()
from sqlalchemy import func
session.query(func.count(User.name), User.name).group_by(User.name).all()
session.query(func.count('*')).select_from(User).scalar()
session.query(func.count(User.id)).scalar()
- 建立关系
from sqlalchemy import ForeignKey
from sqlalchemy.orm import relationship
class Address(Base):
__tablename__ = 'addresses'
id = Column(Integer, primary_key=True)
email_address = Column(String(50), nullable=False)
user_id = Column(Integer, ForeignKey('users.id'))
user = relationship('User', back_populates='addresses')
def __repr__(self):
return '<Address(email_address="%s")>' % self.email_address
User.addresses = relationship('Address', order_by=Address.id, back_populates='users')
Base.metadata.create_all(engine)
- 使用相关对象
jack = User(name='jack', fullname='Jack Bean', nickname='gjffdd')
jack.addresses
jack.addresses = [Address(email_address='jack@google.com'), Address(email_address='j25@yahoo.com')]
jack.addresses[1]
jack.addresses[1].user
session.add(jack)
session.commit()
- join查询
- 基础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, a, sep='\n')
for u in session.query(User).join(Address).filter(Address.email_address=='jack@google.com').all():
print(u)
query.join(Address, User.id==Address.user_id)
query.join(User.addresses)
query.join(Address, User.addresses)
query.join('addresses')
query.outerjoin(User.addresses)
query = session.query(User, Address).select_from(Address).join(User)
- 别名
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)
- 子查询
select users.*, adr_count.address_count from users left outer join
(select user_id, count(*) as address_count from addresses group by user_id) as adr_count
on users.id = adr_count.user_id
stmt = session.query(Address.user_id, func.count('*').label('address_count')).group_by(Address.user_id).subquery()
result = session.query(User, stmt.c.address_count).outerjoin(stmt, User.id==stmt.c.user_id).order_by(User.id)
- 从子查询中映射回实体
stmt = session.query(Address.user_id, func.count('*').label('address_count')).group_by(Address.user_id).subquery()
adalias1 = aliased(Address, stmt)
for user, address in session.query(User, adalias1).join(adalias1, User.addresses):
print(user, address, sep='\t')
- 使用exists
from sqlalchemy.sql import exists
stmt = exists().where(Address.user_id==User.id)
for name, in session.query(User.name).filter(stmt):
print(name)
for name, in session.query(User.name).filter(User.addresses.any()):
print(name)
for name, in session.query(User.name).filter(User.addresses.any(Address.email_address.like('%google%'))):
print(name)
session.query(Address).filter(~Address.user.has(User.name=='jack')).all()
- 常见关系运算符
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'))
query.filter(User.addresses.any(email_address == 'bar'))
query.filter(User.addresses.has(name == 'ed'))
session.query(Address).with_parent(someuser, 'addresses')
- 急切加载
- 选择加载: 会发起第二次select
from sqlalchmey.orm import selectinload
jack = session.query(User).options(selectinload(User.addresses)).filter_by(name='jack').one()
print(jack, jack.addresses, sep='\n')
- 连接加载: 发起left outer join
from sqlalchemy.orm import joinedload
jack = session.query(User).options(joinedload(User.addresses)).filter_by(name='jack').one()
print(jack, jack.addresses, sep='\n')
- Explicit Join + Eagerload
from sqlalchemy.orm import contains_eager
jacks_addresses = session.query(Address).join(Address.user).filter(name=='jack').options(contains_eager(Address.user)).all()
print(jacks_address[0].user, jacks_addresses, sep='\n')
- 删除
session.delete(jack)
session.query(User).filter_by(name='jack').count()
session.query(Address).filter(Address.email_address.in_(['jack@google.com', 'j25@yahoo.com'])).count()
session.close()
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
name = Column(String)
fullname = Column(String)
nickname = Column(String)
address = relationship('Address', back_populates='users', cascade='all, delete, delete-orphan')
def __repr__(self):
return "<User(name='%s', fullname='%s', nickname='%s')>" % (self.name, self.fullname, self.nickname)
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', back_populates='addresses')
def __repr__(self):
return "<Address(email_address='%s')>" % self.email_address
Base.metadata.create_all(engine)
jack = session.query(User).get(5)
del jack.addresses[1]
session.query(Address).filter(Address.email_address.in_(['jack@google.com', 'j25@yahoo.com'])).count()
session.delete(jack)
session.query(User).filter_by(name='jack').count()
session.query(Address).filter(Address.email_address.in_(['jack@google.com', 'j25@yahoo.com'])).count()
- 建立多对多关系
from sqlalchemy import Table, Text
post_keywords = Table("post_keywords", Base.metadata,
Column('post_id', ForeignKey('posts.id'), primary_key=True),
Column('keyword_id', ForeignKey('keywords.id'), primary_key=True)
)
class BlogPost(Base):
__tablename__ = 'posts'
id = Column(Integer, primary_key=True)
user_id = Column(Integer, ForeignKey('users.id'))
headline = Column(String(255), nullable=False)
body = Column(Text)
keywords = relationship('Keyword', secondary=post_keywords, back_populates='posts')
def __init__(self, headline, body, author):
self.author = author
self.headline = headline
self.body = body
def __repr__(self):
return "BlogPost(%r, %r, %r)" % (self.headline, self.body, self.author)
class Keyword(Base):
__tablename__ = 'keywords'
id = Column(Integer, primary_key=True)
keyword = Column(String(50), nullable=False, unique=True)
posts = relationship('BlogPost', secondary=post_keywords, back_populates='keywords')
def __init__(self, keyword):
self.keyword = keyword
BlogPost.author = relationship(User, back_populates="posts")
User.posts = relationship(BlogPost, back_populates="author", lazy="dynamic")
Base.metadata.create_all(engine)
wendy = session.query(User).filter_by(name='wendy').one_or_none()
post = BlogPost("Wendy's Blog Post", "This is a test", wendy)
session.add(post)
post.keywords.append(Keyword('wendy'))
post.keywords.append(Keyword('firstpost'))
session.query(BlogPost).filter(BlogPost.keywords.any(keyword='firstpost')).all()
session.query(BlogPost).filter(BlogPost.author==wendy).filter(BlogPost.keywords.any(keyword='firstpost')).all()
wendy.posts.filter(BlogPost.keywords.any(keyword='firstpost')).all()
- 进一步查考
- Query Reference: Query API
- Mapper Reference: Mapper Configuration
- Relationship Reference: Relationship Configuration
- Session Reference: Using the Session
- link