之前写过一篇博客介绍过sqlalchemy的基本用法,本篇博客主要介绍除增删改查以外SQLAlchemy对数据库表的操作,主要内容有单表操作、一对多操作、多对多操作。
一、单表操作
单表操作的增删改查在上篇博客中已经详细介绍过,这里不再详细介绍,今天主要对数据库查询在详细介绍一下,下面我们先创建表并插入数据。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from
sqlalchemy
import
and_, or_
from
sqlalchemy
import
create_engine
from
sqlalchemy.ext.declarative
import
declarative_base
from
sqlalchemy
import
Column, Integer, String, ForeignKey, UniqueConstraint, Index
from
sqlalchemy.orm
import
sessionmaker, relationship
engine
=
create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/mydata"
, max_overflow
=
5
)
Base
=
declarative_base()
class
Group(Base):
__tablename__
=
'group'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
caption
=
Column(String(
32
))
class
User(Base):
__tablename__
=
'user'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
username
=
Column(String(
32
))
group_id
=
Column(Integer, ForeignKey(
'group.nid'
))
group
=
relationship(
"Group"
,backref
=
'uuu'
)
#跟Group表建立关系,方便查询,常和ForeignKey在一起使用
def
init_table():
"""
创建表,调用Base类的子类
:return:
"""
Base.metadata.create_all(engine)
def
drop_table():
Base.metadata.drop_all(engine)
init_table()
Session
=
sessionmaker(bind
=
engine)
session
=
Session()
# 单表操作:
session.add(Group(caption
=
'dba'
))
#往组里添加数据
session.add(Group(caption
=
'dddd'
))
session.commit()
session.add_all([
User(username
=
'jack1'
,group_id
=
1
),
User(username
=
'jack2'
,group_id
=
1
),
User(username
=
'jack1'
,group_id
=
2
),
User(username
=
'jack1'
,group_id
=
1
),
User(username
=
'jack2'
,group_id
=
1
),
])
session.commit()
|
1,条件查询
1
2
3
4
5
6
7
8
9
|
#查询用户jack1的nid,filter和filter_by两种书写方式
ret1
=
session.query(User.nid).
filter
(User.username
=
=
'jack1'
).
all
()
print
(ret1)
ret2
=
session.query(User.nid).filter_by(username
=
'jack1'
).
all
()
print
(ret2)
#结果:
[(
1
,), (
3
,), (
4
,)]
[(
1
,), (
3
,), (
4
,)]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#查询用户nid大于1并且username等于jack2的nid
ret1
=
session.query(User.nid).
filter
(User.nid >
1
,User.username
=
=
'jack2'
).
all
()
print
(ret1)
#结果:
[(
2
,), (
5
,)]
#查询nid在1和3之间username等于jack1的所有信息
ret2
=
session.query(User.nid,User.username).
filter
(User.nid.between(
1
,
3
),User.username
=
=
'jack1'
).
all
()
print
(ret2)
#结果:
[(
1
,
'jack1'
), (
3
,
'jack1'
)]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
#查询用户nid在1,3,4这个列表里的用户信息
ret
=
session.query(User.nid,User.username).
filter
(User.nid.in_([
1
,
3
,
4
])).
all
()
print
(ret)
#结果:
[(
1
,
'jack1'
), (
3
,
'jack1'
), (
4
,
'jack1'
)]
#取反,查询用户nid不在1,3,4这个列表里的用户信息
ret1
=
session.query(User.nid,User.username).
filter
(~User.nid.in_([
1
,
3
,
4
,])).
all
()
print
(ret1)
#结果:
[(
2
,
'jack2'
), (
5
,
'jack2'
)]
#查询username='jack1'的所有信息
ret2
=
session.query(User.nid,User.username).
filter
(
User.nid.in_(session.query(User.nid).filter_by(username
=
'jack1'
))).
all
()
print
(ret2)
#结果:
[(
1
,
'jack1'
), (
3
,
'jack1'
), (
4
,
'jack1'
)]
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
#查询nid大于3并且username='jack1'的信息
ret
=
session.query(User.nid,User.username).
filter
(and_(User.nid >
3
,User.username
=
=
'jack1'
)).
all
()
print
(ret)
#结果:
[(
4
,
'jack1'
)]
#查询nid小于2或者username等于jack1的数据
ret
=
session.query(User.nid,User.username).
filter
(
or_(User.nid <
2
, User.username
=
=
'jack1'
)).
all
()
print
(ret)
#查询用户nid小于2或者username等于jack1并且nid大于3的信息
ret
=
session.query(User.nid,User.username).
filter
(
or_(User.nid <
2
,and_(User.username
=
=
'jack1'
, User.nid >
3
))).
all
()
print
(ret)
#结果:
[(
1
,
'jack1'
), (
4
,
'jack1'
)]
|
二、通配符
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#模糊匹配用户名以字母j开头的所有数据
ret
=
session.query(User.nid,User.username).
filter
(User.username.like(
'j%'
)).
all
()
#结果:
[(
1
,
'jack1'
), (
2
,
'jack2'
), (
3
,
'jack1'
), (
4
,
'jack1'
), (
5
,
'jack2'
)]
#取反
ret1
=
session.query(User.nid,User.username).
filter
(~User.username.like(
'j%'
)).
all
()
print
(ret)
print
(ret1)
#结果:
[]
|
三、限制
1
2
3
4
5
|
ret
=
session.query(User.nid,User.username)[
1
:
2
]
print
(ret)
#结果:
[(
2
,
'jack2'
)]
|
四、排序
1
2
3
4
5
6
7
8
9
10
11
12
13
|
#倒序排序
ret
=
session.query(User.nid,User.username).order_by(User.nid.desc()).
all
()
print
(ret)
#结果:
[(
5
,
'jack2'
), (
4
,
'jack1'
), (
3
,
'jack1'
), (
2
,
'jack2'
), (
1
,
'jack1'
)]
#正序排序
ret1
=
session.query(User.nid,User.username).order_by(User.nid.asc()).
all
()
print
(ret1)
#结果:
[(
1
,
'jack1'
), (
2
,
'jack2'
), (
3
,
'jack1'
), (
4
,
'jack1'
), (
5
,
'jack2'
)]
|
五、分组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
#导入模块
from
sqlalchemy.sql
import
func
ret
=
session.query(User.nid,User.username).group_by(User.nid).
all
()
print
(ret)
#结果:
[(
1
,
'jack1'
), (
2
,
'jack2'
), (
3
,
'jack1'
), (
4
,
'jack1'
), (
5
,
'jack2'
)]
ret1
=
session.query(
func.
max
(User.nid),
func.
sum
(User.nid),
func.
min
(User.nid),).group_by(User.username).
all
()
print
(ret1)
#结果:
[(
4
, Decimal(
'8'
),
1
), (
5
, Decimal(
'7'
),
2
)]
ret2
=
session.query(
func.
max
(User.nid),
func.
sum
(User.nid),
func.
min
(User.nid), ).group_by(User.username).having(func.
min
(User.nid)>
1
).
all
()
print
(ret2)
#结果:
[(
5
, Decimal(
'7'
),
2
)]
#打印SQL语句:
from
sqlalchemy.sql
import
func
ret2
=
session.query(
func.
max
(User.nid),
func.
sum
(User.nid),
func.
min
(User.nid), ).group_by(User.username).having(func.
min
(User.nid)>
1
)
print
(ret2)
#结果:
SELECT
max
(
"user"
.nid) AS max_1,
sum
(
"user"
.nid) AS sum_1,
min
(
"user"
.nid) AS min_1
FROM
"user"
GROUP BY
"user"
.username
HAVING
min
(
"user"
.nid) > :min_2
[(
'jack1'
,
'dba'
), (
'jack2'
,
'dddd'
)]
SELECT
"user"
.nid AS user_nid,
"user"
.username AS user_username,
"user"
.group_id AS user_group_id
FROM
"user"
LEFT OUTER JOIN
"group"
ON
"group"
.nid
=
"user"
.group_id
|
六、组合
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
q1
=
session.query(User.username).
filter
(User.nid >
2
)
q2
=
session.query(Group.caption).
filter
(Group.nid <
2
)
ret
=
q1.union(q2).
all
()
print
(ret)
#结果:
[(
'jack1'
,), (
'jack2'
,), (
'dba'
,)]
q1
=
session.query(User.username).
filter
(User.nid >
2
)
q2
=
session.query(Group.caption).
filter
(Group.nid <
2
)
ret
=
q1.union_all(q2).
all
()
print
(ret)
#结果:
[(
'jack1'
,), (
'jack1'
,), (
'jack2'
,), (
'dba'
,)]
|
二、一对多操作
一对多的关系就需要我们外键来进行约束,下面我们来举例来说明一对多进行连表操作。
1,原始方式:通过join方法来进行连表操作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
ret
=
session.query(User.username,Group.caption).
filter
(User.nid
=
=
Group.nid).
all
()
print
(ret)
#结果:
[(
'jack1'
,
'dba'
), (
'jack2'
,
'dddd'
)]
#通过join来进行连表操作,加isouter的区别:
sql1
=
session.query(User).join(Group,isouter
=
True
)
print
(sql1)
#结果:
SELECT
"user"
.nid AS user_nid,
"user"
.username AS user_username,
"user"
.group_id AS user_group_id
FROM
"user"
LEFT OUTER JOIN
"group"
ON
"group"
.nid
=
"user"
.group_id
sql2
=
session.query(User).join(Group)
print
(sql2)
#结果:
SELECT
"user"
.nid AS user_nid,
"user"
.username AS user_username,
"user"
.group_id AS user_group_id
FROM
"user"
JOIN
"group"
ON
"group"
.nid
=
"user"
.group_id
#连表操作
ret
=
session.query(User.username,Group.caption).join(Group,isouter
=
True
).
filter
(Group.caption
=
=
'dba'
).
all
()
print
(ret)
#结果:
[(
'jack1'
,
'dba'
), (
'jack2'
,
'dba'
), (
'jack1'
,
'dba'
)]
|
2,新方式:通过建立relationship的方式
1
2
3
4
5
6
7
|
#首先在创建表的类中加入relationship字段
class
User(Base):
__tablename__
=
'user'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
username
=
Column(String(
32
))
group_id
=
Column(Integer, ForeignKey(
'group.nid'
))
group
=
relationship(
"Group"
,backref
=
'uuu'
)
#跟Group表建立关系,方便查询,backref为虚拟列
|
正向查询:通过User表查询Group表
1
2
3
4
5
6
7
8
9
10
11
12
13
|
ret
=
session.query(User).
all
()
for
obj
in
ret:
#obj代指user表的每一行数据
#obj.group代指group对象
print
(obj.nid,obj.username,obj.group_id,obj.group_id,obj.group,
obj.group.nid,obj.group.caption)
#结果:
1
jack1
1
1
<__main__.Group
object
at
0x0000015D762F4630
>
1
dba
2
jack2
1
1
<__main__.Group
object
at
0x0000015D762F4630
>
1
dba
3
jack1
2
2
<__main__.Group
object
at
0x0000015D762F47F0
>
2
dddd
4
jack1
1
1
<__main__.Group
object
at
0x0000015D762F4630
>
1
dba
5
jack2
2
2
<__main__.Group
object
at
0x0000015D762F47F0
>
2
dddd
|
反向查询:通过Group表查询User表
1
2
3
4
5
6
7
8
9
|
obj
=
session.query(Group).
filter
(Group.caption
=
=
'dba'
).first()
print
(obj.nid)
print
(obj.caption)
print
(obj.uuu)
#结果:
1
dba
[<__main__.User
object
at
0x000002606096C5C0
>, <__main__.User
object
at
0x000002606096C630
>, <__main__.User
object
at
0x000002606096C6A0
>]
|
我们可以看到上面的例子输出的为对象的列表,输出不太友好,为了达到自己想要的结果,我们可以进行自定义返回结果,请看下面代码,加入__repr__函数:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
class
User(Base):
__tablename__
=
'user'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
username
=
Column(String(
32
))
group_id
=
Column(Integer, ForeignKey(
'group.nid'
))
group
=
relationship(
"Group"
,backref
=
'uuu'
)
#跟Group表建立关系,方便查询,常和ForeignKey在一起使用
def
__repr__(
self
):
"""
自定义返回结果
:return:
"""
temp
=
'%s:%s:%s'
%
(
self
.nid,
self
.username,
self
.group_id)
return
temp
|
三、多对多操作
1,创建表结构并插入信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from
sqlalchemy
import
create_engine
from
sqlalchemy.ext.declarative
import
declarative_base
from
sqlalchemy
import
Column, Integer, String, ForeignKey, UniqueConstraint, Index
from
sqlalchemy.orm
import
sessionmaker, relationship
engine
=
create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/mydata"
, max_overflow
=
5
)
Base
=
declarative_base()
class
Host(Base):
__tablename__
=
'host'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
hostname
=
Column(String(
32
))
port
=
Column(String(
32
))
ip
=
Column(String(
32
))
class
HostUser(Base):
__tablename__
=
'host_user'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
username
=
Column(String(
32
))
#使用for循环时,通过正向反向查询
class
HostToHostUser(Base):
__tablename__
=
'host_to_host_user'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
host_id
=
Column(Integer,ForeignKey(
'host.nid'
))
host_user_id
=
Column(Integer,ForeignKey(
'host_user.nid'
))
host
=
relationship(
"Host"
,backref
=
'h'
)
host_user
=
relationship(
"HostUser"
,backref
=
'u'
)
def
init_table():
"""
创建表,调用Base类的子类
:return:
"""
Base.metadata.create_all(engine)
def
drop_table():
Base.metadata.drop_all(engine)
init_table()
Session
=
sessionmaker(bind
=
engine)
session
=
Session()
session.add_all([
Host(hostname
=
'c1'
,port
=
'22'
,ip
=
'1.1.1.1'
),
Host(hostname
=
'c2'
,port
=
'22'
,ip
=
'1.1.1.2'
),
Host(hostname
=
'c3'
,port
=
'22'
,ip
=
'1.1.1.3'
),
Host(hostname
=
'c4'
,port
=
'22'
,ip
=
'1.1.1.4'
),
Host(hostname
=
'c5'
,port
=
'22'
,ip
=
'1.1.1.5'
),
])
session.commit()
session.add_all([
HostUser(username
=
'root'
),
HostUser(username
=
'db'
),
HostUser(username
=
'nb'
),
HostUser(username
=
'sb'
),
])
session.commit()
session.add_all([
HostToHostUser(host_id
=
1
,host_user_id
=
1
),
HostToHostUser(host_id
=
1
,host_user_id
=
2
),
HostToHostUser(host_id
=
1
,host_user_id
=
3
),
HostToHostUser(host_id
=
2
,host_user_id
=
2
),
HostToHostUser(host_id
=
2
,host_user_id
=
4
),
HostToHostUser(host_id
=
2
,host_user_id
=
3
),
])
session.commit()
|
2,需求:获取主机1中所有的用户
方法一:通过一步一步取
1
2
3
4
5
6
7
8
9
10
11
12
|
host_obj
=
session.query(Host).
filter
(Host.hostname
=
=
'c1'
).first()
# #取出host_obj.nid
host_to_host_user
=
session.query(HostToHostUser.host_user_id).
filter
(HostToHostUser.host_id
=
=
host_obj.nid).
all
()
#
# #因为取出来的结果是[(1,),(2,),(3,)],我们通过内置函数zip来转换成想要的结果
r
=
zip
(
*
host_to_host_user)
#
users
=
session.query(HostUser.username).
filter
(HostUser.nid.in_(
list
(r)[
0
])).
all
()
print
(users)
#结果:
[(
'root'
,), (
'db'
,), (
'nb'
,)]
|
方法二:通过join的方式
1
2
|
#通过代码整合的代码,相当复杂
session.query(HostUser.name).
filter
(HostUser.nid.in_(session.query(HostToHostUser.host_user_id).
filter
(HostToHostUser.host_id
=
=
session.query(Host.nid).
filter
(Host.hostname
=
=
'c1'
))))
|
方法三:通过建立relationship的方式
1,对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from
sqlalchemy
import
create_engine
from
sqlalchemy.ext.declarative
import
declarative_base
from
sqlalchemy
import
Column, Integer, String, ForeignKey, UniqueConstraint, Index
from
sqlalchemy.orm
import
sessionmaker, relationship
engine
=
create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/mydata"
, max_overflow
=
5
)
Base
=
declarative_base()
class
HostToHostUser(Base):
__tablename__
=
'host_to_host_user'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
host_id
=
Column(Integer,ForeignKey(
'host.nid'
))
host_user_id
=
Column(Integer,ForeignKey(
'host_user.nid'
))
class
Host(Base):
__tablename__
=
'host'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
hostname
=
Column(String(
32
))
port
=
Column(String(
32
))
ip
=
Column(String(
32
))
host_user
=
relationship(
'HostUser'
,secondary
=
HostToHostUser.__table__,backref
=
'h'
)
# host_user = relationship('HostUser', secondary=lambda: HostToHostUser.__table__, backref='h')
#这里加lambda是因为关系表在下面,可以不加lambda,但是关系表要放上面
class
HostUser(Base):
__tablename__
=
'host_user'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
username
=
Column(String(
32
))
def
init_table():
"""
创建表,调用Base类的子类
:return:
"""
Base.metadata.create_all(engine)
def
drop_table():
Base.metadata.drop_all(engine)
Session
=
sessionmaker(bind
=
engine)
session
=
Session()
host_obj
=
session.query(Host).
filter
(Host.hostname
=
=
'c1'
).first()
print
(host_obj.host_user)
|
2,类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from
sqlalchemy
import
create_engine
from
sqlalchemy.ext.declarative
import
declarative_base
from
sqlalchemy
import
Column, Integer, String, ForeignKey, UniqueConstraint, Index
from
sqlalchemy.orm
import
sessionmaker, relationship
engine
=
create_engine(
"mysql+pymysql://root:123456@127.0.0.1:3306/mydata"
, max_overflow
=
5
)
Base
=
declarative_base()
class
HostToHostUser(Base):
__tablename__
=
'host_to_host_user'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
host_id
=
Column(Integer,ForeignKey(
'host.nid'
))
host_user_id
=
Column(Integer,ForeignKey(
'host_user.nid'
))
class
Host(Base):
__tablename__
=
'host'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
hostname
=
Column(String(
32
))
port
=
Column(String(
32
))
ip
=
Column(String(
32
))
host_user
=
relationship(
'HostUser'
,secondary
=
HostToHostUser.__table__,backref
=
'h'
)
# host_user = relationship('HostUser', secondary=lambda: HostToHostUser.__table__, backref='h')
#这里加lambda是因为关系表在下面,可以不加lambda,但是关系表要放上面
class
HostUser(Base):
__tablename__
=
'host_user'
nid
=
Column(Integer, primary_key
=
True
,autoincrement
=
True
)
username
=
Column(String(
32
))
def
init_table():
"""
创建表,调用Base类的子类
:return:
"""
Base.metadata.create_all(engine)
def
drop_table():
Base.metadata.drop_all(engine)
Session
=
sessionmaker(bind
=
engine)
session
=
Session()
host_obj
=
session.query(Host).
filter
(Host.hostname
=
=
'c1'
).first()
print
(host_obj.host_user)
|
今天SQLALchemy就介绍到这里,更多参考信息请参考: