zoukankan      html  css  js  c++  java
  • SQLAlchemy

    以上,SQLAlchemy的两个最重要的前端部分是ORM(Object Relational Mapper,,即对象关系映射器)和 SQL表达式语言。SQL表达式可以独立于ORM使用。使用ORM时,SQL表达式语言仍然是面向对象的API的一部分,因为它在对象关系配置和查询中使用。

    SQLAlchemy是python中的ORM框架。对象关系映射(英语:Object Relation Mapping,简称ORM,或O/RM,或O/R mapping)其他语言中都会有ORM框架,可以进行更加快捷便利的操作数据库。
    SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。

    注意:SQLAlchemy本身无法操作数据库,必须依赖第三方插件如pymysql,mysqlDB,Dialect用于和数据API进行交流,根据配置文件的不同调用不同数据库的API,从而实现对数据库的操作。

    一,创建表

    默认的情况下SQLAlchemy不能修改表结构,可以下载第三方工具进行修改。

    #!/usr/bin/python
    # _*_ coding:utf-8 _*_
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    
    engine = create_engine("mysql+pymysql://root:123@10.1.1.3:3306/s13", max_overflow=5)
    # 创建连接
    
    Base = declarative_base() # 规定的必须要写这一步
    
    # ------------------创建单表-----------------------
    class Users(Base):  #必须继承Base
    	__tablename__ = 'users'
    	id = Column(Integer, primary_key=True)
    	name = Column(String(32))
    	extra = Column(String(16))
    
    	__table_args__ = (            # 创建的联合索引
    	UniqueConstraint('id', 'name', name='uix_id_name'),
    		Index('ix_id_name', 'name', 'extra'),
    	)
    
    
    # -----------------一对多-----------------------
    class Favor(Base):
    	__tablename__ = 'favor'
    	nid = Column(Integer, primary_key=True)
    	caption = Column(String(50), default='red', unique=True)
    
    
    class Person(Base):
    	__tablename__ = 'person'
    	nid = Column(Integer, primary_key=True)
    	name = Column(String(32), index=True, nullable=True)
    	favor_id = Column(Integer, ForeignKey("favor.nid"))
    
    
    # -----------------多对多------------------
    class Group(Base):
    	__tablename__ = 'group'
    	id = Column(Integer, primary_key=True)
    	name = Column(String(64), unique=True, nullable=False)
    	port = Column(Integer, default=22)
    
    
    class Server(Base):
    	__tablename__ = 'server'
    
    	id = Column(Integer, primary_key=True, autoincrement=True)
    	hostname = Column(String(64), unique=True, nullable=False)
    
    
    class ServerToGroup(Base):   # 要想创建多对多的关系,需要创建第三个表保存他们的对应关系
    	__tablename__ = 'servertogroup'
    	nid = Column(Integer, primary_key=True, autoincrement=True)
    	server_id = Column(Integer, ForeignKey('server.id'))
    	group_id = Column(Integer, ForeignKey('group.id'))
    
    
    def init_db():
    	Base.metadata.create_all(engine)  # 找到Base所有的子类,根据类去创建表
    
    
    def drop_db():
    	Base.metadata.drop_all(engine)
    # init_db()   # 创建所有的表
    drop_db() # 删除所有的表
    

      

     二,操作表

    #!/usr/bin/env python
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    
    engine = create_engine("mysql+pymysql://root:123@10.1.1.3:3306/s13", max_overflow=5)
    
    Base = declarative_base()
    
    
    # 创建单表
    class Users(Base):
    	__tablename__ = 'users'
    	id = Column(Integer, primary_key=True)
    	name = Column(String(32))
    	extra = Column(String(16))
    
    	__table_args__ = (
    	UniqueConstraint('id', 'name', name='uix_id_name'),
    		Index('ix_id_name', 'name', 'extra'),
    	)
    
    	def __repr__(self):    # 这个方法是SQLAlchemy内部自己规定的,这个函数对查询没有一点用处,只是在打印对象时方便查看
    		return "%s-%s" %(self.id, self.name)
    
    
    # 一对多
    class Favor(Base):
    	__tablename__ = 'favor'
    	nid = Column(Integer, primary_key=True)
    	caption = Column(String(50), default='red', unique=True)
    
    	def __repr__(self):
    		return "%s-%s" %(self.nid, self.caption)
    
    
    class Person(Base):
    	__tablename__ = 'person'
    	nid = Column(Integer, primary_key=True)
    	name = Column(String(32), index=True, nullable=True)
    	favor_id = Column(Integer, ForeignKey("favor.nid"))
    	# 与生成表结构无关,仅用于查询方便
    	favor = relationship("Favor", backref='pers')
    
    
    # 多对多
    class ServerToGroup(Base):
    	__tablename__ = 'servertogroup'
    	nid = Column(Integer, primary_key=True, autoincrement=True)
    	server_id = Column(Integer, ForeignKey('server.id'))
    	group_id = Column(Integer, ForeignKey('group.id'))
    	group = relationship("Group", backref='s2g')
    	server = relationship("Server", backref='s2g')
    
    
    class Group(Base):
    	__tablename__ = 'group'
    	id = Column(Integer, primary_key=True)
    	name = Column(String(64), unique=True, nullable=False)
    	port = Column(Integer, default=22)
    	# group = relationship('Group',secondary=ServerToGroup,backref='host_list')
    
    
    class Server(Base):
    	__tablename__ = 'server'
    	id = Column(Integer, primary_key=True, autoincrement=True)
    	hostname = Column(String(64), unique=True, nullable=False)
    
    
    def init_db():
    	Base.metadata.create_all(engine)
    
    
    def drop_db():
    	Base.metadata.drop_all(engine)
    
    
    Session = sessionmaker(bind=engine)
    session = Session()
    
    
    # ------增--------
    obj = Users(name="alex0", extra='sb')
    session.add(obj)
    session.add_all([                       # 添加数据
    	Users(name="alex1", extra='sb'),
    	Users(name="alex2", extra='sb'),
    ])
    session.commit()  # 提交
    
    
    # -------删--------
    session.query(Users).filter(Users.id > 2).delete()
    session.commit()
    
    
    # -------改---------
    session.query(Users).filter(Users.id > 2).update({"name": "099"})
    session.query(Users).filter(Users.id > 2).update({Users.name: Users.name + "099"}, synchronize_session=False)
    # 字符串的相加
    session.query(Users).filter(Users.id > 2).update({"num": Users.num + 1}, synchronize_session="evaluate")
    # 数字的相加,synchronize_session="evaluate",这样设置之后就会把值当成数字进行相加。
    session.commit()
    
    
    # --------查-----------
    ret = session.query(Users).all()  # 查询所有,此时返回的是User对象列表
    ret = session.query(Users.name, Users.extra).all()  # 查询两列
    ret = session.query(Users).filter_by(name='alex').all()  # 过滤出name='alex'的所有
    ret = session.query(Users).filter_by(name='alex').first()  # 只取第一条
    
    
    
    # 条件
    ret = session.query(Users).filter_by(name='alex').all()
    ret = session.query(Users).filter(Users.id > 1, Users.name == 'eric').all()   # 是'且'的关系
    ret = session.query(Users).filter(Users.id.between(1, 3), Users.name == 'eric').all()
    ret = session.query(Users).filter(Users.id.in_([1,3,4])).all()
    ret = session.query(Users).filter(~Users.id.in_([1,3,4])).all()
    ret = session.query(Users).filter(Users.id.in_(session.query(Users.id).filter_by(name='eric'))).all()
    
    from sqlalchemy import and_, or_
    ret = session.query(Users).filter(and_(Users.id > 3, Users.name == 'eric')).all()
    ret = session.query(Users).filter(or_(Users.id < 2, Users.name == 'eric')).all()   # 这里是'或'的关系
    ret = session.query(Users).filter(
    	or_(
    		Users.id < 2,
    		and_(Users.name == 'eric', Users.id > 3),
    		Users.extra != ""
    	)).all()
    
    
    # 通配符
    ret = session.query(Users).filter(Users.name.like('e%')).all()
    ret = session.query(Users).filter(~Users.name.like('e%')).all()
    
    # 限制
    ret = session.query(Users)[1:2]   # 相当于mysql中的limit
    
    # 排序
    ret = session.query(Users).order_by(Users.name.desc()).all()
    ret = session.query(Users).order_by(Users.name.desc(), Users.id.asc()).all()  # 按照name排序,name相同再按照id排序
    
    
    # 分组
    from sqlalchemy.sql import func
    
    ret = session.query(Users).group_by(Users.extra).all()
    ret = session.query(
    	func.max(Users.id),
    	func.sum(Users.id),
    	func.min(Users.id)).group_by(Users.name).all()
    
    ret = session.query(
    	func.max(Users.id),
    	func.sum(Users.id),
    	func.min(Users.id)).group_by(Users.name).having(func.min(Users.id) >2).all()
    
    # 连表
    
    ret = session.query(Users, Favor).filter(Users.id == Favor.nid).all()
    ret = session.query(Person).join(Favor).all()  # 默认是join类型为inner join,自动连表(在内部会找foreignkey)
    ret = session.query(Person).join(Favor, isouter=True).all()  # isouter=True表示的是left  join
    
    
    # 组合
    q1 = session.query(Users.name).filter(Users.id > 2)
    q2 = session.query(Favor.caption).filter(Favor.nid < 2)
    ret = q1.union(q2).all()   # 默认去重
    
    q1 = session.query(Users.name).filter(Users.id > 2)
    q2 = session.query(Favor.caption).filter(Favor.nid < 2)
    ret = q1.union_all(q2).all()  # 默认不去重 
    

      

    三,详解一对多


    group

    nid caption
    1 1
    2 2

    user 

    nid username goup_id
    1 lintao 1
    2 lily 1
    3 lucy 1

    创建上述表并对表进行简单的操作

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    engine = create_engine("mysql+pymysql://root:123@10.1.1.3:3306/s13", 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'))  #(引擎必须是InnoDB)创建外键,对两张表进行关联
    	
    # 注意mysql的引擎从5.5.5开始默认引擎是InnoDB, 之前的版本默认是MyISAM引擎,MyISAM不支持外键,此时需要
    # 修改配置文件/etc/my.cnf  在mysqld下面增加一行:default-storage-engine=INNODB,然后重启即可生效。
    
    
    Base.metadata.create_all(engine)   # 创建表
    Base.metadata.drop_all(engine)
    Session = sessionmaker(bind=engine)  # 相当于保持一个会话
    session = Session()
    
    # 创建group表记录
    session.add(Group(caption='dba'))  # 记录逐条添加
    session.add(Group(caption='dbd'))
    session.commit()   #必须提交,否则不会生效
    
    # 创建user表记录
    session.add_all([   # 一次性添加多条记录
    	User(username='lin', group_id=1),
    	User(username='lily', group_id=2),
    	User(username='lucy', group_id=3)   # 此时如果group表中的nid没有为3的,那么此时这条记录就会报错!这就是外键的作用
    ])
    session.commit()
    
    
    # 对表进行操作
    	sql = session.query(User).filter(User.username == "tom")  # 返回的是SQL语句
    	print(sql)
    
    	ret = session.query(User).filter(User.username == "tom").all()  # 返回的是一个对象的列表
    	# 如果返回的对象不知道是什么的话,可以在SQLAlchemy可以用repr方法进行自定制
    	print(ret)
    
    	ret1 = session.query(User.username).filter(User.username == "tom").all()  # 返回的是username这一列,中的'tom'
    	print(ret1)
    
    # 连表查询,这里不用像SQL语句中还要加on字段,这里由SQLAlchemy会在内部自动查找foreignkey
    	sql_1 = session.query(User).join(Group)
    	sql_2 = session.query(User).join(Group, isouter=True)
    	ret2 = session.query(User).join(Group).all()
    	print(sql_1)  # 通过sql语句可以看出默认的是inner join
    	print(sql_2)  # 通过添加isouter = True, 可以更改为left join
    	print(ret2)  # 进行关联查询所有的数据
    

      

    小结:
    1,创建表需要指定外键
    2,类, repr方法(# 这个方法是SQLAlchemy内部自己规定的,这个函数对查询没有一点用处,只是在打印对象时方便查看)
    3,单表
    4,连表 session.query("表一").join("表二").all()

     

    上面我们发现查询在查询的时候只有user表,能不能查到group表呢?

    ret3 = session.query(User, Group).all()  # 返回的是对象
    ret4 = session.query(User.username, User.nid, Group.caption, Group.nid).all()  #返回的是列
    print(ret3)
    print(ret4)
    

      

    下面针对上述表我们提出一个需要:如何获取caption为‘dba’所有的用户名?

    第一种实现方式

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    engine = create_engine("mysql+pymysql://root:123@10.1.1.3:3306/s13", 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='pers')  # 与表结构无关,仅用来查询
        # relationship("类名")
    
        def __repr__(self):  # 这里只是来用打印对象时有用,对于查询无用
            tmp = "%s -- %s :%s" % (self.nid, self.username, self.group_id)
            return tmp
    
    Session = sessionmaker(bind=engine)  # 相当于保持一个会话
    session = Session()
    join连表的方式

    第二种实现方式

    其中第二种实现方式,有分为两种,我们姑且称之为:正向查找和反向查找

    由于连表操作比较麻烦,SQLAlchemy又提供了一个新的功能。在声明外键(ForeignKey)的表中增加一个新的字段,group = relationship("Group", backref='pers'),一般情况下foreikey和relationship在一张表里面。这一功能和Django中的类似。到底这个字段代表什么含义呢?

    1,group字段含义是什么?(正向查找,通过带有关系(relationship)的表向其他地方找)

    #通过user表来查询
    ret = session.query(User).all()
    for obj in ret:
        # obj 代指user表中的每一行数据
        # obj.group 代表的是由Group实例化的对象(对象封装的东西和user相关)
        print(obj.username, obj.group_id, obj.nid)
        print(obj.group, obj.group.nid, obj.group.caption)  # SQLAlchemy在内部做的关联
        print("----------------")
    正向查找

    2,backref=pers字段是什么含义?(反向查找,通过其他表,来找到带有relation的表)

    # 通过group表来查询
    obj = session.query(Group).filter(Group.caption == 'dba').first()
    print(obj.nid)
    print(obj.caption)
    
    print(obj.pers)   
    #注意这里是反向查找,此时的obj.pers代表的是User实例化对象(对象封装的内容和group相关),和正向恰好相反,结合
    正向查找去理解
    反向查找

    注意pers在数据库中并没有真实的表与其对应,只是SQLAlchemy在内存中生成的SQL语句而已。就相当于在group表中增加了一个pear字段,就像表user中的group字段一样。

    四,表创建过程


      1,先把写好的类转换为table对象,
      2,然后根据table对象生成SQL语句

    注意:在python中并没有严格的限制,可以直接用table对象生成SQL语句,一般正式和标准的用法都会用类来生成。在其他语言中只允许用类生成表。

    五,详解多对多

    server

    server_id server_name port ip
    1 c1 xx xxx.xx.xx.x
    2 c2 xx xx.xx.xx.xx
    3 c3 xxxx xx.xxx.xx.x

    server_user

    user_id user_name
    1 tom
    2 lily
    3 lucy

    一台主机可以有多个用户,一个用户又可以同时存在多个主机,这就是多对多的关系,这时需要建立第三张关系表

    relation_table

    sid uid
    1 1
    1 3
    2 2
    3 2
    3 1

    此时还需要对第三张表建立约束:外键,这样可以控制数据的一致性和完整性

     创建表结构并插入数据

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    engine = create_engine("mysql+pymysql://root:123@10.1.1.3:3306/s13", 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))
    
    
    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'))
    
    # Base.metadata.create_all(engine)   # 创建表
    Session = sessionmaker(bind=engine)
    session = Session()
    
    # 添加host表中数据
    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()
    
    # 添加host_user表中数据
    session.add_all([
    	HostUser(username='root'),
    	HostUser(username='db'),
    	HostUser(username='nb'),
    	HostUser(username='sb'),
    ])
    session.commit()
    
    # 添加host_to_host_user表中数据
    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()
    

      

    需求:如何获取主机1中所有的用户?

    方案一:传统方式

    思路:
    1,先通过主机1的主机名在host表,获取主机的nid
    2,在通过主机的nid,在host_to_host_user表中找到对应的host_user_id,为用户的ID
    3,最后在host_user表中找到和用户id相对应的用户的信息

    host_obj = session.query(Host).filter(Host.hostname == 'c1').first()
    # print(host_obj.nid)
    # 1
    
    host_2_host_user = session.query(HostToHostUser.host_user_id).filter(HostToHostUser.host_id == host_obj.nid).all()
    # print(host_2_host_user)
    # [(1,), (2,), (3,)]
    # 如何把它转换为列表,或者元组,
    # >>> li
    # [('a',), ('b',), ('c',)]
    # >>> r = map(lambda x:x[0], li)
    # >>> print(list(r))
    # ['a', 'b', 'c']
    # 也可以用r = zip(*host_2_host_user)--> list(r[0])此时为元组('a', 'b', 'c')
    
    users = session.query(HostUser.username).filter(HostUser.nid.in_(map(lambda x: x[0], host_2_host_user))).all()
    print(users)
    # 注意这里fliter不但支持==,还支持in的操作
    
    执行结果:
    [('root',), ('db',), ('nb',)]
    View Code

    方案二:新方式(常用)

    A

    AB ==> foreign_key relationship

    B

    !/usr/bin/env python
    # _*_ coding:utf-8 _*_
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    engine = create_engine("mysql+pymysql://root:123@10.1.1.3:3306/s13", 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))
    
    
    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') #
        # 增加上面两个字段,多对多就相当于两个一对多
    
    # Base.metadata.create_all(engine)   # 创建表
    Session = sessionmaker(bind=engine)
    session = Session()
    
    # 第三张表对应的对象
    host_obj = session.query(Host).filter(Host.hostname == 'c1').first()
    print(host_obj.nid, host_obj.hostname, host_obj.port)
    print(host_obj.h)  # 此时的h代表的HostToHostUsers实例化的对象(和Host相关的)
    
    # 循环获取第三张表对应的对象
    for item in host_obj.h:
        # print(item.host_user) # 获取HostUser实例化的和关系表相关的内容
        r = item.host_user.username
        print(r)
     思路:先通过反向查找,找到HostToHostUser(即关系表)实例化的对象,然后再通过这个对象获取host_user这个字段,这个字段即代表HostUser(即关系表)对象,此时正向查找到相对应的host表中的uername
    View Code

    方案三:新方式(不常用,不太合理)    对象+类的方法创建的

    A ==> relationship

    AB ==> foreign_key

    B

    这里的关系表和foreign_key没有放在一张表里面

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index, Table  #这里需要导入Table模块
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    
    engine = create_engine("mysql+pymysql://root:123@10.1.1.3:3306/s13", max_overflow=5)
    Base = declarative_base()
    
    
    class HostUser(Base):
        __tablename__ = 'host_user'
        nid = Column(Integer, primary_key=True, autoincrement=True)
        username = Column(String(32))
    
    
    HostToHostUser = Table('host_to_host_user', Base.metadata,
                           Column('host_id', ForeignKey('host.nid'), primary_key=True),
                           Column('host_user_id', ForeignKey('host_user.nid'), primary_key=True),
                           )
    
    
    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, backref='h')
         # 注意这里的secondary为关系表的名字:HostToHostUser
    
    Session = sessionmaker(bind=engine)
    session = Session()
    
    host_obj = session.query(Host).filter(Host.hostname == 'c1').first()
    # print(list(map(lambda x: x.username, host_obj.host_user)))
    for item in host_obj.host_user:
        print(item.username)
    View Code

    方案四:也比较合理,简单

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Integer, String, ForeignKey, UniqueConstraint, Index, Table
    from sqlalchemy.orm import sessionmaker, relationship
    from sqlalchemy import create_engine
    engine = create_engine("mysql+pymysql://root:123@10.1.1.3:3306/s13", max_overflow=5)
    Base = declarative_base()
    
    
    class HostUser(Base):
        __tablename__ = 'host_user'
        nid = Column(Integer, primary_key=True, autoincrement=True)
        username = Column(String(32))
    
    
    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')
        # 注意这里的secondary为:HostToHostUser, __table__为获取的table对象
    
    Session = sessionmaker(bind=engine)
    session = Session()
    
    host_obj = session.query(Host).filter(Host.hostname == 'c1').first()
    # print(list(map(lambda x: x.username, host_obj.host_user)))
    for item in host_obj.host_user:
        print(item.username)
    View Code

    SQLAlchemy总结:


    1,orm自动生成表,然后根据类和对象去生成表
    2,创建表,简单
    3,操作表(其实就是转换SQL语句),需要多练。
      单表
      连表
        right.join, left join, inner join
        关系:
          一对多(一般情况下外键和关系会放到一起,foreignkey,relationship)
          多对多
            多一张表,放的是foreignkey,关联约束
            1,关系表:放关系
            2,A:放关系 ,(B, AB)

    练习的顺序:从上往下练习,能用SQL就用SQL,像涉及到一对多和多对多时,SQLAlchemy比较简单的再考虑用。

     

  • 相关阅读:
    [AX]AX2012激活HTTP适配器AIF端口提示错误“The deployment web site was not found for port”
    [AX]AX2012 嵌套使用Data contract class
    [AX]AX2012 对SSRS报表参数分组
    [AX]AX2012 SSRS报表的语言本地化
    [AX]AX2012 Number sequence framework :(二)实现自定义模块的Number sequence
    [AX]AX3中使用LedgerBalanceSum计算科目余额期间发生额
    [AX]AX2012 域管理员组成员没有权限部署报表
    [C#] 在C#中使用HOOK监视鼠标消息的问题
    服务器端获取客户端信息(时间 etc..)
    MSBuild version 与 ToolsVersion 的区别
  • 原文地址:https://www.cnblogs.com/yang-ning/p/6644175.html
Copyright © 2011-2022 走看看