SQLAlchemy查询之一对多

276 阅读2分钟

以下介绍SQLAlchemy的一对多查询,SQLAlchemy是Python的一个ORM框架,这个框架的进一步封装Flask-SQLAlchemy常用于Flask项目,作为Flask与数据库交互的工具。

from sqlalchemy import create_engine, Column, String, Integer, Boolean, ForeignKey  
from sqlalchemy.orm import declarative_base, Session, relationship  
  
DB_TYPE = 'mysql'  
DB_DRIVE = 'pymysql'  
  
USER = 'root'  
PWD = 'Tomboy_study'  
  
HOST = '192.168.93.130'  
PORT = 3306  
  
DB_NAME = 'study'  
  
  
DB_URI = f'{DB_TYPE}+{DB_DRIVE}://{USER}:{PWD}@{HOST}:{PORT}/{DB_NAME}'  
  
engine = create_engine(DB_URI)  
Base = declarative_base()  
  
  
class Classes(Base):  
__tablename__ = "t_class"  
id = Column(Integer, primary_key=True, autoincrement=True)  
name = Column(String(32), nullable=False, unique=True)  
description = Column(String(256))  
  
# student = relationship('Student')  
  
def __repr__(self):  
return f'<{self.id}, {self.name}, {self.description}>'  
  
  
class Student(Base):  
__tablename__ = 't_student'  
id = Column(Integer, primary_key=True, autoincrement=True)  
name = Column(String(10), nullable=False)  
age = Column(Integer)  
sex = Column(Boolean)  
# 1对多 ForeignKey的关键字要建立在 多一边  
class_id = Column(Integer, ForeignKey('t_class.id'))  
  
# 将主表的数据注入到这个字段  
classes = relationship('Classes', backref='stu')  
  
@property  
def gender(self):  
return "男" if self.sex == 1 else "女"  
  
@gender.setter  
def gender(self, val):  
if val == '男':  
return 1  
else:  
return 0  
  
def to_dict(self):  
return {  
'id': self.id,  
'name': self.name,  
'age': self.age,  
'gender': self.gender  
}  
  
def __repr__(self):  
return f'<{self.id}, {self.name}, {self.age}, {self.gender}>'  
  
  
def create_data():  
stu1 = Student(name="Tomboy", age=27, sex=0, class_id=1)  
stu2 = Student(name="幺叔", age=18, sex=1, class_id=1)  
stu3 = Student(name="盼盼", age=19, sex=0, class_id=1)  
  
clses = Classes(name="79班", description="难忘但并未奉献")  
  
with Session(engine) as sess:  
sess.add(clses)  
  
sess.commit()  
  
with Session(engine) as sess:  
sess.add(stu1)  
sess.add(stu2)  
sess.add(stu3)  
  
sess.commit()  
  
  
def query_data1():  
"""SQL思想 + ORM实现一对多,多对一查询"""  
# 正向查找:根据班级查学生  
with Session(engine) as sess:  
classes = sess.query(Classes).filter(Classes.id == 1).first()  
print(classes)  
stu_list = sess.query(Student).filter(Student.class_id == classes.id).all()  
for stu in stu_list:  
print(stu)  
  
print('\n' + "*" * 20 + "分割线" + "*" * 20 + '\n')  
  
# 反向查找:根据学生查班级  
with Session(engine) as sess:  
stu = sess.query(Student).filter(Student.id == 1).first()  
print(stu)  
classes = sess.query(Classes).filter(Classes.id == stu.id).first()  
print(classes)  
  
  
def query_data2():  
"""  
ORM实现一对多、多对一查询:需要增加relationship字段  
最简单的方式就是两边都添加relationship,因为两边都会用到  
"""  
# 正向查找:根据班级找学生  
with Session(engine) as sess:  
classes = sess.query(Classes).filter(Classes.id == 1).first()  
print(classes)  
stu_list = classes.student  
for stu in stu_list:  
print(stu)  
  
print('\n' + "*" * 20 + "分割线" + "*" * 20 + '\n')  
  
# 反向查找:根据学生查班级  
with Session(engine) as sess:  
stu = sess.query(Student).filter(Student.id == 1).first()  
print(stu)  
classes = stu.classes  
print(classes)  
  
  
def query_data3():  
"""  
query_data2有警告,所以我们一般不会在两方都加relationship  
可以通过给多的一方添加relationship,然后在relationship里面增加属性backref来实现  
没有relationship的一方通过backref指定的字段去访问  
"""  
# 正向查找:根据班级找学生  
with Session(engine) as sess:  
classes = sess.query(Classes).filter(Classes.id == 1).first()  
print(classes)  
stu_list = classes.stu  
for stu in stu_list:  
print(stu)  
  
print('\n' + "*" * 20 + "分割线" + "*" * 20 + '\n')  
  
# 反向查找:根据学生查班级  
with Session(engine) as sess:  
stu = sess.query(Student).filter(Student.id == 1).first()  
print(stu)  
classes = stu.classes  
print(classes)  
  
  
if __name__ == '__main__':  
Base.metadata.create_all(engine)  
# create_data()  
# query_data1()  
# query_data2()  
query_data3()