flask之sqlalchemy ORM 一对多、多对多
一、一对多关系
爱好和人的关系,一个爱好可以对应多个人
1、models 建立表关系
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 | # 1 导入一些模块 import datetime from sqlalchemy import create_engine from sqlalchemy.orm import declarative_base, \ relationship # 新的变成它,老的会有 from sqlalchemy.ext.declarative import declarative_base Warning from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index # 2 得到所有表模型需要继承 基类 Base = declarative_base() class Hobby(Base): __tablename__ = 'hobby' id = Column(Integer, primary_key = True ) caption = Column(String( 50 ), default = '篮球' ) def __str__( self ): return self .caption class Person(Base): __tablename__ = 'person' id = Column(Integer, primary_key = True ) name = Column(String( 32 ), index = True , nullable = True ) # hobby指的是tablename而不是类名,uselist=False hobby_id = Column(Integer, ForeignKey( "hobby.id" )) # 关联字段写在多的一方 # 跟数据库无关,不会新增字段,只用于快速链表操作 # 类名,backref用于反向查询 hobby = relationship( 'Hobby' , backref = 'pers' ) # 等同于django中的relate_name,反向查询替换表名小写的 def __str__( self ): return self .name def __repr__( self ): return self .name |
补充:
1.1 __str__
和 __repr__ 方法
__str__
作用:
-
__str__
方法用于定义对象的“用户友好”字符串表示形式。 -
当你使用
print(obj)
或str(obj)
时,Python 会调用__str__
方法来获取对象的字符串表示。 -
这个方法通常用于向用户展示对象的描述性信息。
1 2 | user = Users(name = "Alice" ) print (user) # 输出: Alice |
__repr__
作用:
-
__repr__
方法用于定义对象的“开发者友好”字符串表示形式。 -
当你直接在交互式环境中输入对象名称(如
obj
)或使用repr(obj)
时,Python 会调用__repr__
方法。 -
这个方法通常用于调试和开发,返回的字符串应该尽可能明确地描述对象的状态。
-
如果
__str__
方法未定义,__repr__
会作为__str__
的备用方法。
1 2 | def __repr__( self ): return f "<User(id={self.id}, name={self.name}, email={self.email})>" |
1.2、 relationship 不会新增成字段只是用于连表查询
hobby = relationship('Hobby', backref='pers')
-
'Hobby'
:-
指定关联的模型类为
Hobby
。
-
-
backref='pers'
:-
在
Hobby
模型中创建一个pers
属性,用于反向查询与该Hobby
关联的所有Person
对象。 -
例如,可以通过
hobby.pers
获取所有喜欢该Hobby
的Person
对象。
-
正向查询
通过 Person
对象访问关联的 Hobby
对象:
1 2 3 4 5 6 7 | person = session.query(Person). all () print (person[ 1 ].name) print (person[ 1 ].hobby) ## 结果 dapeng 乒乓球 |
反向查询
通过 Hobby
对象访问关联的 Person
对象:
1 2 3 4 5 6 7 | hobby = session.query(Hobby). all () print (hobby[ 1 ]) print (hobby[ 1 ].pers) # 获取所有喜欢该 Hobby 的 Person 对象 ## 结果 乒乓球 [jingzhiz, dapeng, lisi] |
2、 一对多关系新增和查询
笨办法:先添加爱好再添加人和对应爱好字段
1 2 3 4 5 6 | hobby = Hobby(caption = '乒乓球' ) session.add(hobby) person = Person(name = 'lisi' , hobby_id = 2 ) # hobby_id=1 只能放数字 session.add(person) session.commit() session.close() |
高级点的用法
hobby 放对象,用对象做关联,但是必须用 relationship
1 2 3 4 5 | hobby = Hobby(caption = '橄榄球' ) person = Person(name = '彭于晏' , hobby = hobby) session.add(person) session.commit() session.close() |
二、多对多关系
1、models创建表关系
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 | # 1 导入一些模块 import datetime from sqlalchemy import create_engine from sqlalchemy.orm import declarative_base, \ relationship # 新的变成它,老的会有 from sqlalchemy.ext.declarative import declarative_base Warning from sqlalchemy import Column, Integer, String, Text, ForeignKey, DateTime, UniqueConstraint, Index # 2 得到所有表模型需要继承 基类 Base = declarative_base() # 多对多 class Boy2Girl(Base): __tablename__ = 'boy2girl' id = Column(Integer, primary_key = True , autoincrement = True ) girl_id = Column(Integer, ForeignKey( 'girl.id' )) boy_id = Column(Integer, ForeignKey( 'boy.id' )) ctime = Column(DateTime, default = datetime.datetime.now) # 约会时间 class Girl(Base): __tablename__ = 'girl' id = Column(Integer, primary_key = True ) name = Column(String( 64 ), unique = True , nullable = False ) # boy = relationship('Boy', secondary='boy2girl', backref='girls') def __repr__( self ): return self .name class Boy(Base): __tablename__ = 'boy' id = Column(Integer, primary_key = True , autoincrement = True ) name = Column(String( 64 ), unique = True , nullable = False ) # 与生成表结构无关,仅用于查询方便,放在哪个单表中都可以,这个字段放boy或girl表都可以 girls = relationship( 'Girl' , secondary = 'boy2girl' , backref = 'boys' ) def __repr__( self ): return self .name # # 4 创建 engine,需要手动创建数据库 engine = create_engine( "mysql+pymysql://root:bigdata@192.168.1.238:3306/sqlalchemy01?charset=utf8" , max_overflow = 0 , # 超过连接池大小外最多创建的连接 pool_size = 5 , # 连接池大小 pool_timeout = 30 , # 池中没有线程最多等待的时间,否则报错 pool_recycle = - 1 # 多久之后对线程池中的线程进行一次连接的回收(重置) ) # 5 通过 engine 把上面的表模型,创建到数据库中 Base.metadata.create_all(engine) |
2、多对多新增和查询
2.1 新增
新增简单用法
1 2 3 4 5 6 7 8 9 | # 先新增人 boy = Boy(name = '张三' ) girl = Girl(name = '小红' ) session.add_all([boy, girl]) # 再新增约会 b = Boy2Girl(girl_id = 1 , boy_id = 1 ) session.add(b) session.commit() |
高级用法
一起新增多个约会
1 2 3 4 5 6 7 | boy = Boy(name = '张五' ) girl = Girl(name = '大红红红' ) # 查出小红 xh = session.query(Girl).filter_by(name = '小红' ).first() boy.girls = [girl, xh] session.add(boy) session.commit() |
2.2 查询
正向查询
1 2 3 | # 查询:张五跟谁约过 zw = session.query(Boy).filter_by(name = '张五' ).first() print (zw.girls) # 基于对象的跨表的正向查询 |
反向查询
1 2 | xh = session.query(Girl).filter_by(name = '小红' ).first() print (xh.boys) # 基于对象的跨表的正向查询 |
注意:
这里的xh.boys 是Boy表中 girls = relationship('Girl', secondary='boy2girl', backref='boys') backref 指定的字段