Sqlalchemy Docs
Sqlalchemy Docs
Categories:
SQLAlchemy 是python中,通过ORM操作数据库的框架。简单点来说,就是帮助我们从烦冗的sql语句中解脱出来,从而不需要再去写原生的sql语句,只需要用python的语法来操作对象,就能被自动映射为sql语句。
Sqlalchemy 简单使用
安装配置
pip install sqlalchemy
初步使用
1# 导入:
2from sqlalchemy import Column, String, create_engine
3from sqlalchemy.orm import sessionmaker
4from sqlalchemy.ext.declarative import declarative_base
5
6# 创建对象的基类:
7Base = declarative_base()
8
9# 定义User对象:
10class User(Base):
11 # 表的名字:
12 __tablename__ = 'user'
13
14 # 表的结构:
15 id = Column(Integer, primary_key=True, autoincrement=True)
16 name = Column(String(20))
17
18# 初始化数据库连接:
19engine = create_engine('mysql+pymysql://root:root@localhost/tmpdb?charset=utf8')
20# 创建DBSession类型:
21DBSession = sessionmaker(bind=engine)
22# 创建session对象:
23session = DBSession()
24# 创建新User对象:
25new_user = User(id='5', name='Bob')
26# 添加到session:
27session.add(new_user)
28# 提交即保存到数据库:
29session.commit()
30# 关闭session:
31session.close()
初始化数据库连接
1engine = create_engine('dialect+driver://username:password@host:port/database')
2# dialect:数据库类型
3# driver:数据库驱动选择
4# username:数据库用户名
5# password: 用户密码
6# host:服务器地址
7# port:端口
8# database:数据库
1# PostgreSQL
2engine = create_engine('postgresql://username:password@localhost/database')
3engine = create_engine('postgresql+psycopg2://username:password@localhost/database')
4engine = create_engine('postgresql+pg8000://username:password@localhost/database')
5
6# Mysql
7engine = create_engine('mysql://username:password@localhost/database')
8engine = create_engine('mysql+mysqldb://username:password@localhost/database')
9engine = create_engine('mysql+mysqlconnector://username:password@localhost/database')
10engine = create_engine('mysql+oursql://username:password@localhost/database')
11engine = create_engine('mysql+pymysql://username:password@localhost/database')
12
13# Oracle
14engine = create_engine('oracle://username:password@127.0.0.1:1521/database')
15engine = create_engine('oracle+cx_oracle://username:password@tnsname')
16
17# Microsoft SQL Server
18engine = create_engine('mssql+pyodbc://username:password@mydsn')
19engine = create_engine('mssql+pymssql://username:password@hostname:port/database')
20
21# SQLite
22engine = create_engine('sqlite:///database.db')
23engine = create_engine('sqlite:absolute/path/to/database.db')
# create_engine 其它可选参数
# echo :为 True 时候会把sql语句打印出来
# pool_size: 是连接池的大小,默认为5个,0表示连接数无限制
# pool_recycle: MySQL 默认情况下如果一个连接8小时内容没有任何动作(查询请求)就会自动断开链接,出现 MySQL has gone away的错误。设置了 pool_recycle 后 SQLAlchemy 就会在指定时间内回收连接。如果设置为3600 就表示 1小时后该连接会被自动回收。
# pool_pre_ping : 这是1.2新增的参数,如果值为True,那么每次从连接池中拿连接的时候,都会向数据库发送一个类似 select 1 的测试查询语句来判断服务器是否正常运行。当该连接出现 disconnect 的情况时,该连接连同pool中的其它连接都会被回收。
MetaData Table
1# 获取元数据
2metadata = MetaData()
3# 定义表
4user = Table('user', metadata,
5 Column('id', Integer, primary_key=True),
6 Column('name', String(20)),
7 )
8
9color = Table('color', metadata,
10 Column('id', Integer, primary_key=True),
11 Column('name', String(20)),
12 )
13
14# 执行sql语句
15engine.execute(
16 "INSERT INTO db_name.color(id, name) VALUES ('1', 'liuyao');"
17)
18result = engine.execute('select * from color')
19print(result.fetchall())
数据模型
1from sqlalchemy.ext.declarative import declarative_base
2from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index
3
4Base = declarative_base()
5
6
7class User(Base):
8 __tablename__ = 'user'
9 id = Column(Integer, primary_key=True, autoincrement=True)
10 name = Column(String(80))
11
12 def __repr__(self):
13 return '<User: {}>'.format(self.name)
14
15
16class Address(Base):
17 __tablename__ = 'address'
18 id = Column(Integer, primary_key=True, autoincrement=True)
19 email = Column(String(80))
20 user_id = Column(Integer, ForeignKey('user.id'))
21
22 def __repr__(self):
23 return "<Address %s %d>" % (self.email, self.user_id)
24
25
26# 清除已有表
27Base.metadata.drop_all(engine)
28# 建立表
29Base.metadata.create_all(engine)
30
31
数据查询
1# 前置数据模型代码
2class User(Base):
3 __tablename__ = 'user'
4 id = Column(Integer, primary_key=True, autoincrement=True)
5 name = Column(String(40), unique=True, nullable=False)
6 email = Column(String(80), nullable=True)
7
8 def __repr__(self):
9 return "<User: %s, %s, %s>" % (self.id, self.name, self.email)
10
11 def to_dict(self):
12 return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}
13
14
15class Course(Base):
16 __tablename__ = 'course'
17 id = Column(Integer, primary_key=True, autoincrement=True)
18 name = Column(String(80))
19 # ForeignKey 设置外键关联,第一个参数为字符串,user 为数据表名,id 为字段名
20 # 第二个参数 ondelete 设置删除 User 实例后对关联的 Course 实例的处理规则
21 # 'CASCADE' 表示级联删除,删除用户实例后,对应的课程实例也会被连带删除
22 user_id = Column(Integer, ForeignKey('user.id', ondelete='CASCADE'))
23 # relationship 设置查询接口,以便后期进行数据库查询操作
24 # 第一个参数为位置参数,参数值为外键关联的映射类名,数据类型为字符串
25 # 第二个参数 backref 设置反向查询接口
26 # backref 的第一个参数 'course' 为查询属性,User 实例使用该属性可以获得相关课程实例的列表
27 # backref 的第二个参数 cascade 如此设置即可实现 Python 语句删除用户数据时级联删除课程数据
28 user = relationship('User',
29 backref=backref('course', cascade='all, delete-orphan'))
30
31 def __repr__(self):
32 return '<Course: %s, %s, %s>' % (self.id, self.name, self.user_id)
33
34 def to_dict(self):
35 return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}
36
37
38class Address(Base):
39 __tablename__ = "address"
40 id = Column(Integer, primary_key=True, autoincrement=True, comment='主键')
41 user_id = Column(Integer, nullable=False, comment='用户ID')
42 addr = Column(String(200), nullable=True)
43
44 def __repr__(self):
45 return '<Address %s, %s>' % (self.user_id, self.addr)
46
47 def to_dict(self):
48 return {c.name: getattr(self, c.name, None) for c in self.__table__.columns}
1userquery = session.query(User)
2lst = [
3 # 条件查询
4 userquery.filter(User.id > 3).all(),
5 userquery.filter(User.id > 4).all()[:3],
6 session.query(User.name).filter(User.id > 4).all(),
7 userquery.filter(User.id == 3).first(),
8 userquery.filter(User.id == 5).one(),
9 userquery.filter(User.id.between(3,6)).all(),
10 # 限制返回条数
11 userquery.filter(User.id > 0).all(),
12 userquery.filter(User.id > 0).limit(2).all(),
13 userquery.filter(User.id > 0).offset(2).all(),
14 userquery.filter(User.id > 0).slice(2, 3).all(),
15 # 条件排序
16 userquery.filter(User.id > 0).order_by(User.id).all(),
17 userquery.filter(User.id > 0).order_by(desc(User.id)).all(),
18 userquery.filter(User.id > 0).order_by(User.id.asc()).all(),
19 userquery.filter(User.id > 0).order_by(User.id.desc()).all(),
20 # 不等于
21 userquery.filter(User.id != 3).all(),
22 # 模糊匹配 like, not like
23 userquery.filter(User.email.like('%ao%')).all(),
24 userquery.filter(User.email.notlike('%ao%')).all(),
25 # 匹配
26 userquery.filter(User.email.startswith("a")).all(),
27 userquery.filter(User.email.endswith("g")).all(),
28 userquery.filter(User.email.contains("ao")).all(),
29 # 属于in_ 不属于 notin_
30 userquery.filter(User.id.in_([1, 3, 5])).all(),
31 userquery.filter(User.id.notin_((1, 3, 5))).all(),
32 # 空判断
33 userquery.filter(User.name == None).all(),
34 userquery.filter(User.name.is_(None)).all(),
35 userquery.filter(User.name.isnot(None)).all(),
36 # 多条件
37 userquery.filter(User.id > 3, User.id < 5).all(),
38 userquery.filter(User.id > 3).filter(User.id < 5).all(),
39 # 选择条件
40 userquery.filter(or_(User.id < 2, User.id > 9)).all(),
41 userquery.filter(and_(User.id > 3, User.id < 6)).all(),
42 # 去重
43 userquery.filter(User.id > 3).distinct().all(),
44 # 聚合函数
45 session.query(Course.user_id, func.count(Course.user_id).label('number')).group_by(Course.user_id).all(),
46 session.query(Course.user_id, func.count(Course.user_id).label('number')).group_by(Course.user_id).having(func.count(Course.user_id) > 1).all(),
47 session.query(Course.user_id, func.sum(Course.user_id).label('number')).group_by(Course.user_id).all(),
48 session.query(Course.user_id, func.max(Course.user_id).label('number')).group_by(Course.user_id).all(),
49 session.query(Course.user_id, func.min(Course.user_id).label('number')).group_by(Course.user_id).all(),
50 # 使用extract提取时间中的分钟或者天来分组
51 session.query(extract('minute', User.creatime).label('minute'), func.count('*').label('count')).group_by('minute').all(),
52 session.query(extract('day', User.creatime).label('day'), func.count('*').label('count')).group_by('day').all(),
53 # Join
54 有外键
55 session.query(User.id, User.name.label('uname'), Course.name.label("cname")).join(Course).filter(User.id > 4).all(),
56 无外键, 指定关联关系
57 session.query(User.id, User.name, Address.addr).join(Address, User.id == Address.user_id).filter(User.id > 5).all(),
58 # text 直接写sql
59 userquery.filter(text("id>:id")).params(id=4).all(),
60
61]
62
63# 外连接
64smtp = session.query(User).filter(User.id > 5).subquery()
65lst.append(session.query(smtp.c.name, Address.addr).outerjoin(smtp, Address.user_id == smtp.c.id).all())
66
67
68for res in lst:
69 print(res)
70 # 单对象
71 # data = [r.to_dict() for r in res]
72 # print(data)
73 # 多表查询时
74 # data = [dict(zip(result.keys(), result)) for result in res]
75 # print(data)
76 print("*" * 30)
模型关系
使用代码维护表间外键关联
1class Blog(Base):
2 __tablename__ = 'blog'
3
4 id = Column(BIGINT, primary_key=True, autoincrement=True)
5 title = Column(String(64), server_default='', nullable=False)
6 text = Column(Text, nullable=False)
7 user = Column(BIGINT, nullable=False) # Column(BIGINT, ForeignKey('user.id'), index=True, nullable=False)
8 create = Column(BIGINT, index=True, server_default='0', nullable=False)
9
10 def __repr__(self):
11 return '<Course: %s, %s, %s>' % (self.id, self.title, self.user)
12
13class User(Base):
14 __tablename__ = 'user'
15
16 id = Column(BIGINT, primary_key=True, autoincrement=True)
17 name = Column(String(32), server_default='', nullable=False)
18 username = Column(String(32), index=True, server_default='', nullable=True)
19 password = Column(String(64), server_default='', nullable=False)
20
21 def __repr__(self):
22 return '<Course: %s, %s, %s>' % (self.id, self.name, self.username)
23
24
25# 查询
26print( session.query(User).all() )
27pirnt( session.query(Blog).all() )
28print( session.query(Blog).join(User, user.id==Blog.user).all() )
使用数据库维护表间外键关联
1class Blog(Base):
2 __tablename__ = 'blog'
3
4 id = Column(BIGINT, primary_key=True, autoincrement=True)
5 title = Column(String(64), server_default='', nullable=False)
6 text = Column(Text, nullable=False)
7 user = Column(BIGINT, ForeignKey('user.id'), index=True, nullable=False)
8 create = Column(BIGINT, index=True, server_default='0', nullable=False)
9
10 def __repr__(self):
11 return '<Course: %s, %s, %s>' % (self.id, self.title, self.user)
12
13class User(Base):
14 __tablename__ = 'user'
15
16 id = Column(BIGINT, primary_key=True, autoincrement=True)
17 name = Column(String(32), server_default='', nullable=False)
18 username = Column(String(32), index=True, server_default='', nullable=True)
19 password = Column(String(64), server_default='', nullable=False)
20
21 def __repr__(self):
22 return '<Course: %s, %s, %s>' % (self.id, self.name, self.username)
23
24
25# 查询
26print( session.query(User).all() )
27pirnt( session.query(Blog).all() )
28print( session.query(Blog).join(User).filter(User.id==3).all() )
backref & back_populates
1# backref 只要一边写上就可以
2class User(Base):
3 __tablename__ = 'user'
4 id = Column(Integer, primary_key=True, autoincrement=True)
5 name = Column(String(80))
6
7 addresses = relationship("Address", backref="user")
8
9 def __repr__(self):
10 return '<User: {}>'.format(self.name)
11
12
13class Address(Base):
14 __tablename__ = 'address'
15 id = Column(Integer, primary_key=True, autoincrement=True)
16 email = Column(String(80))
17 user_id = Column(Integer, ForeignKey('user.id'))
18
19 def __repr__(self):
20 return "<Address %s %d>" % (self.email, self.user_id)
21
22# back_populates 要两边都写上
23class User(Base):
24 __tablename__ = 'user'
25 id = Column(Integer, primary_key=True, autoincrement=True)
26 name = Column(String(80))
27
28 addresses = relationship("Address", back_populates="user")
29
30 def __repr__(self):
31 return '<User: {}>'.format(self.name)
32
33
34class Address(Base):
35 __tablename__ = 'address'
36 id = Column(Integer, primary_key=True, autoincrement=True)
37 email = Column(String(80))
38 user_id = Column(Integer, ForeignKey('user.id'))
39
40 user = relationship("User", back_populates="addresses")
41
42 def __repr__(self):
43 return "<Address %s %d>" % (self.email, self.user_id)
44
45# 查询
46
47user = session.query(User).get(3)
48print(user, user.address)
49addr = session.qeury(Address).get(3)
50print(addr, addr.user)
一对多关联
1class Parent(Base): # 一
2 __tablename__ = 'parent'
3 id = Column(Integer, primary_key=True)
4 name = Column(String(64), nullable=False)
5 children = relationship("Child", backref=backref('parents'))
6
7
8class Child(Base): # 多
9 __tablename__ = 'child'
10 id = Column(Integer, primary_key=True)
11 name = Column(String(64), nullable=False)
12 parent_id = Column(Integer, ForeignKey('parent.id'))
13
14# 一对多 一方
15# children = relationship("Child", backref=backref('parents'), cascade="all, delete-orphan")
16# 一对多 多方
17# parents = relationship("Parent", backref=backref('children', cascade="all, delete-orphan"))
18# 以上可以级联删除
一对一关联
1
多对多关联
1