Sqlalchemy加载实例事件未触发

时间:2019-11-27 21:28:34

标签: python sqlalchemy flask-sqlalchemy

我正在尝试自定义从数据库加载的对象。

根据文档here,该事件应在加载对象时触发,但不会。

如何启动“加载实例”事件? 这是我的代码

# test.py
from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer, event
from sqlalchemy.orm import mapper, scoped_session, sessionmaker
from sqlalchemy_utils.functions import create_database, drop_database


engine = create_engine('sqlite:///sqlite3.db')
engine.connect()

metadata = MetaData(engine)

user_table = Table('user', metadata, 
    Column('id', Integer(), primary_key=True),
    Column('name', String(200), nullable=False),
)

class User:

    def __init__(self, *args, **kwargs):
        pass


def receive_load(target, context):
    print("listen for the 'load' event")


event.listen(User, 'load', receive_load)

mapper(User, user_table)
create_database(engine.url)
metadata.create_all()

session_factory = scoped_session(sessionmaker(engine),)
session = session_factory()

user = User()
user.id = 1
user.name = 'ashwin'

session.add(user)
session.flush()
session.commit()

new_session = session_factory()

obj = new_session.query(User).filter_by(id=1).first() # Event should fire here when I run this line
drop_database(engine.url)

1 个答案:

答案 0 :(得分:0)

我从sqlalchemy的创建者本人那里得到了sqlalchemy github问题的答案,将其重新发布在这里,以便其他人也觉得它有用。

https://github.com/sqlalchemy/sqlalchemy/issues/5008

基本上,该错误是我实际上没有在代码中创建两个不同的会话,因为session_factory()两次都返回了相同的会话,因为它是线程范围的会话。

如果我将代码分成两个单独的脚本,然后一个接一个地运行它们,则可以看到load事件触发。

# test1.py
from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer, event
from sqlalchemy.orm import mapper, scoped_session, sessionmaker
from sqlalchemy_utils.functions import create_database, drop_database
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///sqlite3.db')
engine.connect()

metadata = MetaData(engine)

user_table = Table('user', metadata, 
    Column('id', Integer(), primary_key=True),
    Column('name', String(200), nullable=False),
)

class User:

    def __init__(self, *args, **kwargs):
        pass


Base = declarative_base()

mapper(User, user_table)


create_database(engine.url)
metadata.create_all()

session_factory = scoped_session(sessionmaker(engine),)

session = session_factory()

user = User()
user.id = 1
user.name = 'ashwin'

session.add(user)
session.flush()
session.commit()

from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer, event
from sqlalchemy.orm import mapper, scoped_session, sessionmaker
from sqlalchemy_utils.functions import create_database, drop_database
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///sqlite3.db')
engine.connect()

metadata = MetaData(engine)

user_table = Table(
    'user', 
    metadata,
    Column('id', Integer(), primary_key=True),
    Column('name', String(200), nullable=False),
)


class User:

    def __init__(self, *args, **kwargs):
        pass


def receive_load(target, context):
    print("listen for the 'load' event")
    print(target)
    print(context)

def receive_refresh(target, context, only_load_props=None):
    print("listen for the 'refresh' event")


event.listen(User, 'load', receive_load)
event.listen(User, "refresh", receive_load)

Base = declarative_base()

mapper(User, user_table)


session_factory = scoped_session(sessionmaker(engine),)

new_session = session_factory()

# Event should fire here when I run this line
obj = new_session.query(User).filter_by(id=1).first()
drop_database(engine.url)

并且,如果我需要使其在同一脚本中工作,则需要调用session_factory.remove()来处置第一个会话。

from sqlalchemy import create_engine, MetaData, Table, Column, String, Integer, event
from sqlalchemy.orm import mapper, scoped_session, sessionmaker
from sqlalchemy_utils.functions import create_database, drop_database
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///sqlite3.db')
engine.connect()

metadata = MetaData(engine)

user_table = Table('user', metadata,
    Column('id', Integer(), primary_key=True),
    Column('name', String(200), nullable=False),
)


class User:

    def __init__(self, *args, **kwargs):
        pass


def receive_load(target, context):
    print("listen for the 'load' event")
    print(target)
    print(context)


def receive_refresh(target, context, only_load_props=None):
    print("listen for the 'refresh' event")


event.listen(User, 'load', receive_load)
event.listen(User, "refresh", receive_load)

Base = declarative_base()

mapper(User, user_table)


create_database(engine.url)
metadata.create_all()

session_factory = scoped_session(sessionmaker(engine),)

session_factory.remove()

session = session_factory()

user = User()
user.id = 1
user.name = 'ashwin'

session.add(user)
session.flush()
session.commit()

session_factory = scoped_session(sessionmaker(engine),)

new_session = session_factory()

# Event should fire here when I run this line
obj = new_session.query(User).filter_by(id=1).first()
drop_database(engine.url)