多對一連表操作
首先有兩個知識點:
- 改變數據輸出的方式:可以在表的類中定義一個特殊成員:__repr__,return一個自定義的由字符串拼接的數據連接方式.
- 數據庫中表關系之間除了MySQL中標准的外鍵(ForeignKey)之外,還可以創建一個虛擬的關系,比如
group = relationship("Group",backref='uuu')
,一般此虛擬關系與foreignkey一起使用.
需求:
- 用戶組,有sa,dba組
- 用戶,用戶只能屬於一個用戶組
那么從需求可以看出來,是一個一對多的
遍歷表中數據
接着,我們先來看下數據庫中的表結構:
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:7ujm8ik,@192.168.4.193:3306/testsql", 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)
name = Column(String(32))
group_id = Column(Integer,ForeignKey('group.nid'))
###虛擬創建關系,relationship 一般是跟foreginkey 在一起使用
group = relationship("Group",backref='uuu')
#自定義輸出方式
def __repr__(self):
temp = '%s-%s:%s'%(self.nid,self.name,self.group_id)
return temp
##插入數據
# session.add_all([
# Group(caption='DBA'),
# Group(caption='SA')
# ])
# session.add_all([
# User(name='alex',group_id=1),
# User(name='alex2',group_id=1),
# User(name='cc',group_id=2)
# ])
#
# session.commit()
查詢user表中的所有數據:
sql=session.query(User).join(Group,isouter=True)
print(sql)
ret =session.query(User).join(Group,isouter=True).all()
print(ret)
結果:
SELECT "user".nid AS user_nid, "user".name AS user_name, "user".group_id AS user_group_id
FROM "user" LEFT OUTER JOIN "group" ON "group".nid = "user".group_id
[3-alex:1, 4-alex2:1, 5-cc:2]
無虛擬關系的原始查詢方式
需求:查詢user表中姓名並且顯示各自的所屬組
ret = session.query(User.name,Group.caption).join(Group,isouter=True).all()
print(ret)
結果:
[('alex', 'DBA'), ('alex2', 'DBA'), ('cc', 'SA')]
虛擬關系的查詢方式
正向查詢
需求:查詢user表中所有數據,並且顯示對應的用戶組表中的數據.
首先肯定要設定一個虛擬關系啦,group = relationship("Group",backref='uuu')
看下代碼:
#正向查詢
ret = session.query(User).all()
for obj in ret:
# #obj 代指user表的每一行數據
# #obj.group 代指group對象
print(obj.nid,obj.name,obj.group_id,obj.group,obj.group.nid,obj.group.caption)
結果:
3 alex 1 <__main__.Group object at 0x10387eba8> 1 DBA
4 alex2 1 <__main__.Group object at 0x10387eba8> 1 DBA
5 cc 2 <__main__.Group object at 0x10387ed68> 2 SA
注意:多對一正向查詢,一條命令即可,直接看對象中的屬性即可
反向查詢原始方式
需求:查詢用戶組表中屬於DBA組的用戶名
ret=session.query(User.name,Group.caption).join(Group,isouter=True).filter(Group.caption=='DBA').all()
print(ret)
結果:
[('alex', 'DBA'), ('alex2', 'DBA')]
虛擬關系反向查詢方式
需求:查詢用戶組中屬於DBA組的用戶名
#反向查詢
#group中得到一個對象
obj=session.query(Group).filter(Group.caption=='DBA').first()
print(obj.nid)
print(obj.caption)
#連接到虛擬關系中backref設定的uuu
print(obj.uuu)
結果:
1
DBA
[3-alex:1, 4-alex2:1]
注意:多對一反向查詢,需要遍歷對象屬性
多對多連表操作
需求以及數據庫結構
需求:
三張表:
- 主機表:包括nid hostname port ip
- 管理員表:包括:nid username
- 主機對應管理員表: nid 主機id,管理員id
一個管理員帳號(比如root),可以關聯多台服務器,一個服務器也可以有多個管理員帳號
先來看下數據結構吧:
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:7ujm8ik,@192.168.4.193:3306/testsql", 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'))
#多對多操作
host = relationship('Host',backref='h')
host_user = relationship('HostUser',backref='u')
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')
class HostUser(Base):
__tablename__ = 'host_user'
nid = Column(Integer, primary_key=True,autoincrement=True)
username = Column(String(32))
def init_db():
Base.metadata.create_all(engine)
# init_db()
def drop_db():
Base.metadata.drop_all(engine)
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()
無虛擬關系的原始方式
需求:查詢主機C1的管理員帳號
#1.先在host表中查詢c1的nid
host_obj = session.query(Host).filter(Host.hostname=='c1').first()
#2.查詢hosttohostuer表中的所有host_id等於c1的nid的對應的host_user_id
host_2_host_user = session.query(HostToHostUser.host_user_id).filter(HostToHostUser.host_id==host_obj.nid).all()
# print(host_2_host_user)
r=zip(*host_2_host_user)
# print(list(list(r)[0]))
#通過查到的host_user_id查詢hostuser表中的對應的管理員用戶名
users = session.query(HostUser.username).filter(HostUser.nid.in_(list(list(r)[0]))).all()
print(users)
結果:
[('root',), ('db',), ('nb',)]
是不是很麻煩?
虛擬關系的查詢
需求:同上,查詢主機C1的管理員帳號
# 1.反向查找,查詢host表中c1的信息,會得到一個對象,對象中存在一個已經設置好的虛擬關系:h
host_obj = session.query(Host).filter(Host.hostname == 'c1').first()
#2.正向查找,遍歷對象屬性
for item in host_obj.h:
print(item.host_user.username)
結果:
root
db
nb
注意:多對多的話,正反查詢都是遍歷對象中的屬性
同一需求最簡單的方式
需求還是同上:查詢主機C1的管理員帳號
需要在兩張表的一張表中加一條host_user=relationship('HostUser',secondary=HostToHostUser.__table__,backref='h')
,我加到了host表中
#最簡單的查詢方式:
host_obj = session.query(Host).filter(Host.hostname == 'c1').first()
print(host_obj.host_user)
for item in host_obj.host_user:
print(item.username)
結果:
[<__main__.HostUser object at 0x103778710>, <__main__.HostUser object at 0x103778d68>, <__main__.HostUser object at 0x103778e10>]
root
db
nb