Flask-SQLAlchemy删除对象后变量仍有效是否属于正常行为?
问题描述
我用以下代码创建了两个数据库表:
class User(db.Model): id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) email = db.Column(db.String(100), unique=True) password = db.Column(Password) name = db.Column(db.String(1000)) studies = db.relationship('Study', backref='owner', lazy=True, cascade='save-update, merge, delete') class Study(db.Model): id = db.Column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4) owner_id = db.Column(UUID(as_uuid=True), db.ForeignKey('user.id'), nullable=False)
我正在测试删除用户时其关联的Study是否会被一并删除,目前测试用例的断言均通过:
def test_studies_removed_with_user(app): user = User.query.filter_by(email=app.config['TESTUSER_EMAIL']).first() study = Study(owner=user) db.session.add(study) db.session.commit() assert study db.session.delete(user) db.session.commit() assert User.query.filter_by(email=app.config['TESTUSER_EMAIL']).first() is None assert not Study.query.filter_by(owner_id=user.id).all()
但调试时发现,执行删除并提交后,user和study变量仍有值,我本以为这些变量会失效。请问这是预期行为还是我操作有误?
解答
这是完全符合预期的行为,不存在操作错误。
原因很简单:user和study是内存中的Python对象,你执行的db.session.delete(user)和commit()操作只是把数据库里对应的记录删掉了,但并不会直接销毁内存中已经存在的对象实例。
SQLAlchemy的会话(session)在提交删除操作后,只会把这些对象标记为已删除状态,但不会立即从内存中清除它们——毕竟Python的对象生命周期由垃圾回收机制管理,只有当没有任何引用指向这些对象时,垃圾回收才会把它们回收。
你的测试断言之所以能通过,是因为你重新查询了数据库,确认数据库里的记录已经被删除,这才是验证级联删除是否生效的正确方式。而内存中的变量保留值,完全不影响数据库操作的结果,也不是bug。
如果想让这些变量不再访问到旧数据,可以手动解除引用(比如把user = None、study = None),或者调用db.session.expire_all()让会话中的所有对象失效,后续访问这些对象的属性时会重新从数据库加载(但此时数据库里已经没有记录,会抛出异常)。
内容的提问来源于stack exchange,提问作者chronos
相关产品推荐
相关产品推荐

