SQLAlchmy模块详解

   之前写过一篇博客介绍过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就介绍到这里,更多参考信息请参考:

 

转载于:https://www.cnblogs.com/phennry/p/5731299.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值