SQLAlchemy 会话在实例化纯 python 模型时以某种方式隐式创建条目
SQLAlchemy session somehow implicitly creates entry when instantiating pure python model
我发现 SQLAlchemy
有一些我意想不到的行为。在 many-to-many
关系的特定场景中,即使从未调用 add()
方法,也会将条目添加到 session
对象。
代码:
# orm.py
metadata = MetaData()
class Student:
id: int
classes: list
def __init__(self, classes: list, id: int = None):
self.id = id
self.classes = classes
class Class:
id: int
students: list
def __init__(self, students: list, id: int = None):
self.id = id
self.students = students
students = Table(
'students',
metadata,
Column('id', Integer, primary_key=True),
)
classes = Table(
'classes',
metadata,
Column('id', Integer, primary_key=True)
)
student_classes = Table(
'student_classes',
metadata,
Column('student_id', Integer, ForeignKey('students.id')),
Column('class_id', Integer, ForeignKey('classes.id')),
UniqueConstraint('student_id', 'class_id'),
)
def start_mappers():
mapper(Student, students, properties={
'classes': relationship(Class, secondary=student_classes, back_populates='students')
})
mapper(Class, classes, properties={
'students': relationship(Student, secondary=student_classes, back_populates='classes')
})
# test.py
class Test(unittest.TestCase):
def test_adding_students_and_classes(self):
engine = create_engine('sqlite:///:memory:')
metadata.create_all(engine)
session_factory = sessionmaker(bind=engine)
start_mappers()
session = session_factory()
student = Student(classes=[])
session.add(student)
a_class = Class(students=[student])
self.assertEqual(session.query(Class).count(), 0) # fails because count() = 1
上面的测试失败了,因为创建一个纯 python 模型的 Class
实例会以某种方式隐式触发一个条目添加到会话中。
我很困惑,因为我希望会话只会在显式调用文档中特定的方法之一时发生变化,例如 add()
或 delete()
.
此外,我很困惑 SQLAlchemy
是如何意识到我正在创建 Class
的实例的。有某种听众吗?
调用mapper(Class, ...)
工具Class
,所以它不再“纯粹”了。定义的关系似乎使用默认 cascade configuration, which includes save-update。在这种情况下,因为 Student
实例已添加到会话中,它也会通过其 students
关系在会话中拉取 Class
实例。默认情况下,自动刷新在每个查询之前启动,并且由于 Class
处于待处理状态,因此它会在
之前持久化
session.query(Class).count()
是运行。
我发现 SQLAlchemy
有一些我意想不到的行为。在 many-to-many
关系的特定场景中,即使从未调用 add()
方法,也会将条目添加到 session
对象。
代码:
# orm.py
metadata = MetaData()
class Student:
id: int
classes: list
def __init__(self, classes: list, id: int = None):
self.id = id
self.classes = classes
class Class:
id: int
students: list
def __init__(self, students: list, id: int = None):
self.id = id
self.students = students
students = Table(
'students',
metadata,
Column('id', Integer, primary_key=True),
)
classes = Table(
'classes',
metadata,
Column('id', Integer, primary_key=True)
)
student_classes = Table(
'student_classes',
metadata,
Column('student_id', Integer, ForeignKey('students.id')),
Column('class_id', Integer, ForeignKey('classes.id')),
UniqueConstraint('student_id', 'class_id'),
)
def start_mappers():
mapper(Student, students, properties={
'classes': relationship(Class, secondary=student_classes, back_populates='students')
})
mapper(Class, classes, properties={
'students': relationship(Student, secondary=student_classes, back_populates='classes')
})
# test.py
class Test(unittest.TestCase):
def test_adding_students_and_classes(self):
engine = create_engine('sqlite:///:memory:')
metadata.create_all(engine)
session_factory = sessionmaker(bind=engine)
start_mappers()
session = session_factory()
student = Student(classes=[])
session.add(student)
a_class = Class(students=[student])
self.assertEqual(session.query(Class).count(), 0) # fails because count() = 1
上面的测试失败了,因为创建一个纯 python 模型的 Class
实例会以某种方式隐式触发一个条目添加到会话中。
我很困惑,因为我希望会话只会在显式调用文档中特定的方法之一时发生变化,例如 add()
或 delete()
.
此外,我很困惑 SQLAlchemy
是如何意识到我正在创建 Class
的实例的。有某种听众吗?
调用mapper(Class, ...)
工具Class
,所以它不再“纯粹”了。定义的关系似乎使用默认 cascade configuration, which includes save-update。在这种情况下,因为 Student
实例已添加到会话中,它也会通过其 students
关系在会话中拉取 Class
实例。默认情况下,自动刷新在每个查询之前启动,并且由于 Class
处于待处理状态,因此它会在
session.query(Class).count()
是运行。