一对多表设计和查询方法

#!/usr/bin/env python3
# Author: Zhangxunan from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index, Table
from sqlalchemy.orm import sessionmaker, relationship # 连接数据库
engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/test", max_overflow=5) # 创建基类,所有创建表的类都要继承这个基类
Base = declarative_base() # 创建会话,通过会话去操作数据库
Session = sessionmaker(bind=engine)
session = Session() # 一对多关系(一个组可以有很多人,一个人只能属于一个组)
class Group(Base):
__tablename__ = 'groups'
nid = Column(Integer, primary_key=True,autoincrement=True)
caption = Column(String(32)) class User(Base):
__tablename__ = 'users'
nid = Column(Integer, primary_key=True,autoincrement=True)
username = Column(String(32))
group_id = Column(Integer, ForeignKey('groups.nid'))
group = relationship("Group", backref='user') def init_db():
"""
通过上面的类创建表
:return: None
"""
Base.metadata.create_all(engine) def drop_db():
"""
删除表
:return: None
"""
Base.metadata.drop_all(engine) # 插入数据
# session.add_all([
# Group(caption='SA'),
# Group(caption='DEV'),
# Group(caption='TEST'),
# Group(caption='DBA')
# ])
# session.commit() # session.add_all([
# User(username='tom', group_id=1),
# User(username='jerry', group_id=1),
# User(username='jack', group_id=2),
# User(username='rose', group_id=3),
# User(username='eric', group_id=4),
# User(username='james', group_id=4)
# ])
#
# session.commit() # 输出原生sql
sql = session.query(User.username, Group.caption).join(Group, isouter=True).filter(User.username == 'jack')
print(sql) # 查询jack属于哪个组
ret = session.query(User.username, Group.caption).join(Group, isouter=True).filter(User.username == 'jack').first()
print(ret) # 输出原生sql
sql = session.query(User.username, Group.caption).join(Group, isouter=True)
print(sql) # 查询所有用户分别属于哪个组
ret = session.query(User.username, Group.caption).join(Group, isouter=True).all()
print(ret) # 输出原生sql
sql = session.query(User.username, Group.caption).join(Group, isouter=True).filter(Group.caption == 'SA')
print(sql) # 查询SA组有哪些人
ret = session.query(User.username, Group.caption).join(Group, isouter=True).filter(Group.caption == 'SA').all()
print(ret) # 正向查询 (group = relationship("Group", backref='user'),通过这一句建立关系,然后可以通过这种关系查询更方便)
# 查询jack用户属于哪个组
ret = session.query(User).filter(User.username == 'jack').first()
print(ret.username, ret.group.caption) # 查询所有用户分别属于哪个组
ret = session.query(User).all()
for obj in ret:
# obj代指user表的每一行数据
# obj.group代指group对象,
print(obj.nid, obj.username, obj.group.caption) # 反向查询
# 查询SA组有哪些人
obj = session.query(Group).filter(Group.caption == 'SA').first()
# obj 指代groups表里组名为SA的那一行数据
# obj.user 指代users对象(组为SA的用户数据)
for item in obj.user:
print(item.username, end=' ')

多对多的表设计和查询方法

#!/usr/bin/env python3
# Author: Zhangxunan
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index, Table
from sqlalchemy.orm import sessionmaker, relationship # 连接数据库
engine = create_engine("mysql+pymysql://root:123456@127.0.0.1:3306/test", max_overflow=5) # 创建基类,所有创建表的类都要继承这个基类
Base = declarative_base() # 创建会话,通过会话去操作数据库
Session = sessionmaker(bind=engine)
session = Session() # 多对多(需要第三张表,专门用来存关系,一个用户可以登录多个服务器,一个服务器上可以有多个用户)
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=lambda: HostToHostUser.__table__, backref='host') class HostUser(Base):
__tablename__ = 'host_user'
nid = Column(Integer, primary_key=True,autoincrement=True)
username = Column(String(32)) def init_db():
"""
通过上面的类创建表
:return: None
"""
Base.metadata.create_all(engine) def drop_db():
"""
删除表
:return: None
"""
Base.metadata.drop_all(engine) # session.add_all([
# Host(hostname='web1', port='22', ip='192.168.1.65'),
# Host(hostname='web2', port='22', ip='192.168.1.66'),
# Host(hostname='web3', port='22', ip='192.168.1.67'),
# Host(hostname='web4', port='22', ip='192.168.1.68'),
# Host(hostname='web5', port='22', ip='192.168.1.69'),
# ])
# session.commit() # session.add_all([
# HostUser(username='root'),
# HostUser(username='tom'),
# HostUser(username='jerry'),
# HostUser(username='jack'),
# HostUser(username='rose'),
# ])
# 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() # 需求:获取web1服务器中的所有用户
# 原始方式需要经过三步:
# 第一步:查询web1的服务器ID
host_obj = session.query(Host).filter(Host.hostname == 'web1').first()
print(host_obj.nid) # 第二步:查询第三张表(关系表)查询所有用户的ID host_id == host_obj.nid
host_2_host_user = session.query(HostToHostUser.host_user_id).filter(HostToHostUser.host_id == host_obj.nid).all()
uids = list(zip(*host_2_host_user))[0]
print(uids) # 第三步:根据用户ID查找所有用户
users = session.query(HostUser.username).filter(HostUser.nid.in_(uids)).all()
users = [x[0] for x in users]
print(users) # 当然也可以把上面三步合成一个sql,但太长了 # 正向查询
# host_user = relationship('HostUser', secondary=lambda: HostToHostUser.__table__, backref='host')
# 上面这个话的意思是说给通过第三张表HostToHostUser给HostUser表建立关系
# host_obj是一个对象,是表示hostname=='web1'的那一行数据 host_obj.nid为web1的nid
host_obj = session.query(Host).filter(Host.hostname == 'web1').first()
for item in host_obj.host_user:
print(item.username, end=' ') # 需求2:获取tom用户可以登录哪些服务器
# 原始方式需要经过三步
# 第一步:查询tom用户的id
user_obj = session.query(HostUser).filter(HostUser.username == 'tom').first()
print(user_obj.nid) # 第二步:查询第三张表(关系表),查询所有服务器的ID, 条件是 user_obj.nid == host_user_id
host_ids = session.query(HostToHostUser.host_id).filter(HostToHostUser.host_user_id == user_obj.nid).all()
host_ids = list(zip(*host_ids))[0]
print(host_ids) # 第三步: 根据服务器ID查找服务器hostname
hosts = session.query(Host).filter(Host.nid.in_(host_ids)).all()
hosts = [x.hostname for x in hosts]
print(hosts) # 反向查询
# host_user = relationship('HostUser', secondary=lambda: HostToHostUser.__table__, backref='host')
# 上面这个话的意思是说给通过第三张表HostToHostUser给HostUser表建立关系
host_user_obj = session.query(HostUser).filter(HostUser.username == 'tom').first()
for item in host_user_obj.host:
print(item.hostname, end=' ')
print()

Python之路第十三天,高级(7)-详述数据库一对多,多对多表关系的设计以及如何查询的更多相关文章

  1. Python之路第十二天,高级(5)-Python操作Mysql,SqlAlchemy

    Mysql基础 一.安装 Windows: 1.下载 http://dev.mysql.com/get/Downloads/MySQL-5.6/mysql-5.6.31-winx64.zip 2.解压 ...

  2. Python之路第十二天,高级(4)-Python操作rabbitMQ

    rabbitMQ RabbitMQ是一个在AMQP基础上完整的,可复用的企业消息系统.他遵循Mozilla Public License开源协议. MQ全称为Message Queue, 消息队列(M ...

  3. Python之路第九天,高级(1)-网络编程

    SOCKET编程 socket通常也称作"套接字",用于描述IP地址和端口,是一个通信链的句柄,应用程序通常通过"套接字"向网络发出请求或者应答网络请求. so ...

  4. Python之路(第二十三篇) 面向对象初级:静态属性、静态方法、类方法

    一.静态属性 静态属性相当于数据属性. 用@property语法糖装饰器将类的函数属性变成可以不用加括号直接的类似数据属性. 可以封装逻辑,让用户感觉是在调用一个普通的数据属性. 例子 class R ...

  5. Python之路(第十三篇)time模块、random模块、string模块、验证码练习

    一.time模块 三种时间表示 在Python中,通常有这几种方式来表示时间: 时间戳(timestamp) : 通常来说,时间戳表示的是从1970年1月1日00:00:00开始按秒计算的偏移量.(从 ...

  6. Python之路第十二天,高级(6)-paramiko

    paramiko 一.安装 pip3 install paramiko 二.使用 SSHClient 用于连接远程服务器并执行基本命令 1. 基于用户和密码链接 import paramiko # 创 ...

  7. 测开之路八十三:高级函数:map()和filter()

    # map(函数名,可迭代对象)# 给可迭代对象的每个值+5l = list(range(1, 21)) def add_number(x):    return x + 5 # 第一种方式print ...

  8. Python之路【第二十五篇】:数据库之pymysql模块

    数据库进阶 一.pymysql模块 pymysql是Python中操作Mysql的模块,其使用的方法和py2的MySQLdb几乎相同. 二.pymysql模块安装 pip install pymysq ...

  9. Python之路【第二十四篇】:数据库索引

    数据库索引 一.索引简介 索引在mysql中也叫做"键",是存储引擎用于快速找到记录的一种数据结构.索引对于良好的性能非常关键,尤其是当表中的数据量越来越大时,索引对于性能的影响愈 ...

随机推荐

  1. JavaIO学习总结一

    Java IO 输入输出 一.概念 Java中输入输出操作是以流的方式进行的,流是Java内存中的一组有序数据序列.Java将数据从源(文件.内存.控制台.网络)读入到内存中,形成了流,然后将这些流还 ...

  2. javascript if 和else 语句练习

    1.标准体重://男士体重=身高-100±3<br />//女士体重=身高-110±3<br />//输入性别.身高.体重,查看体重是否标准. <script type= ...

  3. android添加edittext后布局就不好用

    在布局添加控件手动添加还是拖的添加,添加edittext后布局就不好用,其他控件好用,然后就说下面这段话 Exception raised during rendering: java.lang.Sy ...

  4. hdu 2807 The Shortest Path

    http://acm.hdu.edu.cn/showproblem.php?pid=2807 第一次做矩阵乘法,没有优化超时,看了别人的优化的矩阵乘法,就过了. #include <cstdio ...

  5. 【转】Android NDK开发入门实例

    写这个,目的就是记录一下我自己的NDK是怎么入门的.便于以后查看,而不会忘了又用搜索引擎一顿乱搜.然后希望能够帮助刚学的人入门. 先转一段别人说的话:“NDK全称:Native Development ...

  6. 初步swift语言学习笔记9(OC与Swift杂)

    笔者:fengsh998 原文地址:http://blog.csdn.net/fengsh998/article/details/34440159 转载请注明出处 假设认为文章对你有所帮助,请通过留言 ...

  7. Android窗口管理服务WindowManagerService计算窗口Z轴位置的过程分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8570428 通过前面几篇文章的学习,我们知道了 ...

  8. Git 提供篇

    1. Git自动补全 假使你使用命令行工具运行Git命令,那么每次手动输入各种命令是一件很令人厌烦的事情.为了解决这个问题,你可以启用Git的自动补全功能,完成这项工作仅需要几分钟. 为了得到这个脚本 ...

  9. 虚拟化之docker

    1,什么是docker dokcer是应用容器,它是基于系统的虚拟化,他不是基于硬件的虚拟化(KVM),可能这样说有点抽象,我在知乎看到过一个比喻, docker思想是来源于集装箱的,在一艘大船上,可 ...

  10. EffectiveC#2--为你的常量选择readonly而不是const

    1.对于常量,C#里有两个不同的版本: 编译时常量--效率相比更高些,但可维护性不好,保留的目的是为了性能.const关键字申明 public const int _Millennium = 2000 ...