在 SQLAlchemy 中是否可以从 Table 转储和加载(而不是从映射的 class)?
In SQLAlchemy is it possible to dump and load from a Table (not from a mapped class)?
TL;DR 使用 SQLAlchemy is it possible to do a dumps(…)
and load(…)
using a Table
(not a mapped class)? Just to clarify, I wrote those two tiny tests (currently red) 来表达我的观点。
映射 class 和会话:
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.serializer import loads, dumps
from sqlalchemy.orm import mapper, scoped_session
from sqlalchemy.orm.session import sessionmaker
engine = create_engine('sqlite:///:memory:', echo=False)
Base = declarative_base(bind=engine)
session = scoped_session(sessionmaker())
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
email = Column(String(140), index=True, unique=True)
使用 User
映射 class 我可以转储和加载数据:
>>> # create a record
>>> Base.metadata.create_all()
>>> session.add(User(email='john@alchemydumps'))
>>> session.commit()
>>>
>>> # use dumps
>>> with open('dummy_file', 'wb') as file_handler:
... file_handler.write(dumps(session.query(User).all()))
...
490
>>>
>>> # reset the database
>>> Base.metadata.drop_all()
>>> Base.metadata.create_all()
>>>
>>> # use loads
>>> with open('dummy_file', 'rb') as file_handler:
... for row in loads(file_handler.read()):
... session.merge(row)
...
<__main__.User object at 0x10977ea20>
>>> session.commit()
>>>
>>> # assert data is back
>>> session.query(User).count()
1
>>>
但是使用 Table
代替 不 工作:
>>> …
>>>
>>> # use a table instead (User.__table__, instead of User)
>>> with open('dummy_file', 'wb') as file_handler:
... file_handler.write(dumps(session.query(User.__table__).all()))
...
115
>>> Base.metadata.drop_all()
>>> Base.metadata.create_all()
>>>
>>> with open('dummy_file', 'rb') as file_handler:
... for row in loads(file_handler.read()):
... session.merge(row)
...
此代码因 sqlalchemy.orm.exc.UnmappedInstanceError
:
而崩溃
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
File "/Users/cuducos/.virtualenvs/alchemydumps/lib/python3.5/site-packages/sqlalchemy/orm/scoping.py", line 157, in do
return getattr(self.registry(), name)(*args, **kwargs)
File "/Users/cuducos/.virtualenvs/alchemydumps/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 1702, in merge
object_mapper(instance) # verify mapped
File "/Users/cuducos/.virtualenvs/alchemydumps/lib/python3.5/site-packages/sqlalchemy/orm/base.py", line 266, in object_mapper
return object_state(instance).mapper
File "/Users/cuducos/.virtualenvs/alchemydumps/lib/python3.5/site-packages/sqlalchemy/orm/base.py", line 288, in object_state
raise exc.UnmappedInstanceError(instance)
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'sqlalchemy.util._collections.KeyedTuple' is not mapped
这条消息已经太长了,所以我避免过多谈论问题的背景。但是我确实有 a situation,我需要在其中转储和加载未映射的 classes……我正试图为此找到解决方案。 (免责声明:我在 2 年前写了这个包,当时我还是 Python 的新手;是的,代码看起来很糟糕 — 但我在过去几周一直在完全重构它。)
对这个 SQLAlchemy 新手有什么想法或建议吗?
在@univerio 的评论之后,我可以更好地了解情况并修复,耶!
问题在于,如果 SQLAlchemy dumps
收到一个 Table
实例,结果与 table 无关,它们纯粹是一个 KeyedTuple
。所以我不得不:
- 在
KeyedTuple
加载 时引入 映射 class
- transform the
KeyedTuple
into a dictionary(这很容易,因为 KeyedTuple
有一个 _asdict()
方法)
- 然后合并(因为这是我的初衷)
tests are now green,但总结一下这是我需要的:
with open('dummy_file', 'rb') as file_handler:
... for row in loads(file_handler.read()):
... if isinstance(row, KeyedTuple):
... row = User(**row._asdict())
... session.merge(row)
>>> session.commit()
TL;DR 使用 SQLAlchemy is it possible to do a dumps(…)
and load(…)
using a Table
(not a mapped class)? Just to clarify, I wrote those two tiny tests (currently red) 来表达我的观点。
映射 class 和会话:
from sqlalchemy import Column, Integer, String, create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.serializer import loads, dumps
from sqlalchemy.orm import mapper, scoped_session
from sqlalchemy.orm.session import sessionmaker
engine = create_engine('sqlite:///:memory:', echo=False)
Base = declarative_base(bind=engine)
session = scoped_session(sessionmaker())
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True)
email = Column(String(140), index=True, unique=True)
使用 User
映射 class 我可以转储和加载数据:
>>> # create a record
>>> Base.metadata.create_all()
>>> session.add(User(email='john@alchemydumps'))
>>> session.commit()
>>>
>>> # use dumps
>>> with open('dummy_file', 'wb') as file_handler:
... file_handler.write(dumps(session.query(User).all()))
...
490
>>>
>>> # reset the database
>>> Base.metadata.drop_all()
>>> Base.metadata.create_all()
>>>
>>> # use loads
>>> with open('dummy_file', 'rb') as file_handler:
... for row in loads(file_handler.read()):
... session.merge(row)
...
<__main__.User object at 0x10977ea20>
>>> session.commit()
>>>
>>> # assert data is back
>>> session.query(User).count()
1
>>>
但是使用 Table
代替 不 工作:
>>> …
>>>
>>> # use a table instead (User.__table__, instead of User)
>>> with open('dummy_file', 'wb') as file_handler:
... file_handler.write(dumps(session.query(User.__table__).all()))
...
115
>>> Base.metadata.drop_all()
>>> Base.metadata.create_all()
>>>
>>> with open('dummy_file', 'rb') as file_handler:
... for row in loads(file_handler.read()):
... session.merge(row)
...
此代码因 sqlalchemy.orm.exc.UnmappedInstanceError
:
Traceback (most recent call last):
File "<stdin>", line 3, in <module>
File "/Users/cuducos/.virtualenvs/alchemydumps/lib/python3.5/site-packages/sqlalchemy/orm/scoping.py", line 157, in do
return getattr(self.registry(), name)(*args, **kwargs)
File "/Users/cuducos/.virtualenvs/alchemydumps/lib/python3.5/site-packages/sqlalchemy/orm/session.py", line 1702, in merge
object_mapper(instance) # verify mapped
File "/Users/cuducos/.virtualenvs/alchemydumps/lib/python3.5/site-packages/sqlalchemy/orm/base.py", line 266, in object_mapper
return object_state(instance).mapper
File "/Users/cuducos/.virtualenvs/alchemydumps/lib/python3.5/site-packages/sqlalchemy/orm/base.py", line 288, in object_state
raise exc.UnmappedInstanceError(instance)
sqlalchemy.orm.exc.UnmappedInstanceError: Class 'sqlalchemy.util._collections.KeyedTuple' is not mapped
这条消息已经太长了,所以我避免过多谈论问题的背景。但是我确实有 a situation,我需要在其中转储和加载未映射的 classes……我正试图为此找到解决方案。 (免责声明:我在 2 年前写了这个包,当时我还是 Python 的新手;是的,代码看起来很糟糕 — 但我在过去几周一直在完全重构它。)
对这个 SQLAlchemy 新手有什么想法或建议吗?
在@univerio 的评论之后,我可以更好地了解情况并修复,耶!
问题在于,如果 SQLAlchemy dumps
收到一个 Table
实例,结果与 table 无关,它们纯粹是一个 KeyedTuple
。所以我不得不:
- 在
KeyedTuple
加载 时引入 映射 class
- transform the
KeyedTuple
into a dictionary(这很容易,因为KeyedTuple
有一个_asdict()
方法) - 然后合并(因为这是我的初衷)
tests are now green,但总结一下这是我需要的:
with open('dummy_file', 'rb') as file_handler:
... for row in loads(file_handler.read()):
... if isinstance(row, KeyedTuple):
... row = User(**row._asdict())
... session.merge(row)
>>> session.commit()