Python操作SQLAlchemy之连表操作
多对一连表操作
首先有两个知识点:
- 改变数据输出的方式:可以在表的类中定义一个特殊成员:__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
Python操作SQLAlchemy之连表操作的更多相关文章
- Python/MySQL(二、表操作以及连接)
Python/MySQL(二.表操作以及连接) mysql表操作: 主键:一个表只能有一个主键.主键可以由多列组成. 外键 :可以进行联合外键,操作. mysql> create table y ...
- Python - SQLAlchemy之连表操作
ORM的两种创建方式 数据库优先:指的是先创建数据库,包括表和字段的建立,然后根据数据库生成ORM的代码,它是先创建数据库,再创建相关程序代码 代码优先:就是先写代码,然后根据代码去生成数据库结构. ...
- sqlalchemy模块介绍、单表操作、一对多表操作、多对多表操作、flask集成.
今日内容概要 sqlalchemy介绍和快速使用 单表操作增删查改 一对多 多对多 flask集成 内容详细 1.sqlalchemy介绍和快速使用 # SQLAlchemy是一个基于 Python实 ...
- python——Django(ORM连表操作)
千呼万唤始出来~~~当当当,终于系统讲了django的ORM操作啦!!!这里记录的是django操作数据库表一对多.多对多的表创建及操作.对于操作,我们只记录连表相关的内容,介绍增加数据和查找数据,因 ...
- python全栈开发day62-两表操作增删改查,外键,if else模板语法
一.今日内容总结: day62 内容回顾: 1. django有关所有命令: pip install django==1.11.14 django-admin startproject 项目名称 cd ...
- sqlalchemy 学习-- 多表操作
一对多:一对一 # one -- many class Students(Base): __tablename__ = "students" sid = Column(Intege ...
- sqlalchemy 学习--单表操作
以下所有代码片段都使用了统一的引用,该引用如下: from sqlalchemy import create_engine, ForeignKey from sqlalchemy.ext.declar ...
- Python:Day55 ORM多表操作
命令行创建UTF8数据库: CREATE DATABASE 数据库名称 DEFAULT CHARSET utf8 COLLATE utf8_general_ci; 创建多表(外键)
- 5月8日 python学习总结 mysql 建表操作
一 .创建表的完整语法 create table 表名( 字段名1 类型[(宽度) 约束条件],字段名2 类型[(宽度) 约束条件],字段名3 类型[(宽度) 约束条件]); 解释: 类型:使用限制字 ...
随机推荐
- ML之监督学习算法之分类算法一 ———— k-近邻算法(最邻近算法)
一.概述 最近邻规则分类(K-Nearest Neighbor)KNN算法 由Cover 和Hart在1968年提出了最初的邻近算法, 这是一个分类(classification)算法 输入基于实例的 ...
- android在不加载图片的前提下获得图片的宽高
public static int[] getImageWidthHeight(String path){ BitmapFactory.Options options = new BitmapFact ...
- [Aaronyang] 写给自己的WPF4.5 笔记5[数据绑定三巴掌1/3]
生活总有意外,微笑对待每一件事,无需抱怨--Aaronyang的博客(www.ayjs.net) 博文摘要:数据库下载 教你如何在vs2013中不安装Mssql数据库,使用了Sqlserver Com ...
- golang学习笔记 ----读写文件
使用io/ioutil进行读写文件 ioutil包 其中提到了两个方法: func ReadFile func ReadFile(filename string) ([]byte, error) Re ...
- chrome表单自动填充导致input文本框背景变成偏黄色问题解决
chrome表单自动填充后,input文本框的背景会变成偏黄色的,想必大家都会碰到这种情况吧, 这是由于chrome会默认给自动填充的input表单加上input:-webkit-autofill私有 ...
- 认识LINQ的第一步---从查询表达式开始
学习和使用C#已经有2个月了,在这两个月的学习中,深刻体会到,C#这门语言还真不适合编程初学者学习,因为它是吸取了很多其他语言,不仅是面向对象,还包括函数式语言的很多特性,导致它变成特性大爆炸的语言. ...
- DVWA默认用户名密码
有些东西不好找啊,自己动手丰衣足食-- DVWA默认的用户有5个,用户名密码如下(一个足以): admin/password gordonb/abc123 1337/charley pablo/let ...
- Gradle 1.12用户指南翻译
http://blog.csdn.net/maosidiaoxian/article/category/2219983
- jQuery学习笔记(jquery.form插件)
官网: http://malsup.com/jquery/form/ jQuery Form插件是一个优秀的Ajax表单插件,可以非常容易地.无侵入地升级HTML表单以支持Ajax.jQuery Fo ...
- Android Studio 1.1.0 向导页(首页) 解析,以及版本控制 (SVN 和 GIT 的检出)
使用Android Studio首先要理清楚, Android Studio 的 project 相当于Eclipse的 Workspace Android Studio 的 module 相当于E ...