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 指定的字段

 

posted @   凡人半睁眼  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)

阅读目录(Content)

此页目录为空

点击右上角即可分享
微信分享提示