我正在开发一个项目,使用SQLAlchemy和金字塔框架将本地数据加载到本地服务器上。以下描述了设置:
- 本地数据分为多个CSV文件
- 从每个单独的CSV文件
创建单独的SQL对象(称为DataSource)- 所有DataSource的父级也是DataSource。因此,所有CSV数据都是子项
因此,创建了父DataSource,然后创建了所有子DataSource并将其链接到父级。单独的函数检查DataSource是否已存在。如果没有,则创建它。
所以,首先我们创建父DS:
sName = 'Parent DS'
oDS = fetch_or_create_data_source(name=sName,author="Parent_DS_author"
)
然后我们遍历所有CSV并创建子DS:
for sCSV_name in lCSVs:
oChildDS = fetch_or_create_data_source(name=sCSV_name,parent=oDS)
问题在于:
fetch_or_create_data_source在CSV加载的第二次迭代中创建一个keyerror。因此创建父级和第一个子DataSources没有问题。下面的错误日志是在第二个子DS上创建的。应该创建一个新的DS,因为不存在具有给定父级和名称的DS。所有CSV文件名都是唯一的 任何人都可以看到为什么我在DS创建的第二次迭代中得到一个神秘的密钥错误?我在网上找不到任何东西。
(编辑):我知道错误是在lDS = list(oDS.filter_by(name=name).filter_by(parent=parent))
中创建的,但我不明白为什么,特别是在前两次运行后没有问题。我更改了代码,以便调用parent_id而不是父对象,但KeyError仍然存在。该错误是由任何filter_by()
语句引起的。为了检查原始值,我添加了一些print语句来检查fetch_or_create_data_source中的参数。结果:
name = 'Parent DS' type <type 'str'>
author = 'Parent_DS_author' type <type 'str'>
parent = None
Current DS id = '352' type <type 'int'>
.
.
name = 'tab19' type <type 'str'>
author = '' type <type 'str'>
parent = <pyramidapp.models.DataSource object at 0x7fcb28066b50>
parent_id = 352 type <type 'int'>
Current DS id = '353' type <type 'int'>
.
.
name = 'tab42' type <type 'str'>
author = '' type <type 'str'>
parent = <pyramidapp.models.DataSource object at 0x7fcb28066b50>
parent_id = 352 type <type 'int'>
当我明确声明oDS为None时,键错误来自第3次迭代中的DBSession.flush()。
为什么fetch_or_create_data_source的前两个实例运行没有问题,但第三个不是?
代码和追溯:
fetch_or_create_data_source:
def fetch_or_create_data_source(name,parent=None,author=""):
from pyramidapp.models import DBSession,DataSource
oDS = DBSession.query(DataSource)
print "name = '{0}' type {1}".format(name,type(name))
print "author = '{0}' type {1}".format(author,type(author))
print "parent = {0}".format(parent)
if parent:
print "parent_id = {0} type {1}".format(parent.id,type(parent.id))
if parent is None:
lDS = list(oDS.filter_by(name=name).filter_by(parent_id=parent))
else:
lDS = list(oDS.filter_by(name=name).filter_by(parent_id=parent.id)) <=== Key error from here
if len(lDS)==0:
oDS = None
else:
oDS = lDS[0]
if not oDS:
oDS = DataSource()
oDS.name = name
if parent:
oDS.parent = parent
if parent.author:
oDS.author = parent.author
if author:
oDS.author = author
DBSession.add(oDS)
DBSession.flush()
print "Current DS id = '{0}' type {1}".format(oDS.id,type(oDS.id))
return oDS
Pyramidapp.models.DataSource:
class DataSource(Base):
"""
this represents a release of data. It may be a group of documents
or a single spreadsheet
"""
__tablename__ = 'data_sources'
id = Column(Integer,Sequence('data_src_seq'),primary_key=True)
name = Column(String(100))
notes = Column(Text)
title = Column(String(100))
author = Column(String(100))
parent_id = Column(Integer,ForeignKey('data_sources.id'))
parent = relationship('DataSource',backref=backref("children",cascade="all, delete"),remote_side=[id,])
.
.
...
Traceback (most recent call last):
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/pyramid_debugtoolbar-2.0.2-py2.7.egg/pyramid_debugtoolbar/panels/performance.py", line 55, in resource_timer_handler
result = handler(request)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/pyramid-1.5b1-py2.7.egg/pyramid/tweens.py", line 21, in excview_tween
response = handler(request)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/pyramid_tm-0.7-py2.7.egg/pyramid_tm/__init__.py", line 82, in tm_tween
reraise(*exc_info)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/pyramid_tm-0.7-py2.7.egg/pyramid_tm/__init__.py", line 63, in tm_tween
response = handler(request)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/pyramid-1.5b1-py2.7.egg/pyramid/router.py", line 163, in handle_request
response = view_callable(context, request)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/pyramid-1.5b1-py2.7.egg/pyramid/config/views.py", line 355, in rendered_view
result = view(context, request)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/pyramid-1.5b1-py2.7.egg/pyramid/config/views.py", line 477, in _class_requestonly_view
response = getattr(inst, attr)()
File "/home/roman/Critical_ID/big_data/pyramidapp/pyramidapp/views/basic_views.py", line 108, in run_ds_script
oScript.run(dSettings)
File "/home/roman/Critical_ID/big_data/pyramidapp/pyramidapp/scripts/data_source_specific/load_prescriptions_dispensed_in_the_community_data.py", line 82, in run
oChildDS = fetch_or_create_data_source(name=sCSV_name,parent=oDS)
File "/home/roman/Critical_ID/big_data/pyramidapp/pyramidapp/tools/data_source_script_tools.py", line 22, in fetch_or_create_data_source
lDS = list(oDS.filter_by(name=name).filter_by(parent_id=parent.id))
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/query.py", line 2397, in __iter__
self.session._autoflush()
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/session.py", line 1184, in _autoflush
self.flush()
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/session.py", line 1879, in flush
self._flush(objects)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/session.py", line 1997, in _flush
transaction.rollback(_capture_exception=True)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/util/langhelpers.py", line 57, in __exit__
compat.reraise(exc_type, exc_value, exc_tb)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/session.py", line 1961, in _flush
flush_context.execute()
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/unitofwork.py", line 370, in execute
rec.execute(self)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/unitofwork.py", line 523, in execute
uow
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/persistence.py", line 64, in save_obj
mapper, table, insert)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/orm/persistence.py", line 594, in _emit_insert_statements
execute(statement, params)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/engine/base.py", line 717, in execute
return meth(self, multiparams, params)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/sql/elements.py", line 317, in _execute_on_connection
return connection._execute_clauseelement(self, multiparams, params)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/engine/base.py", line 814, in _execute_clauseelement
compiled_sql, distilled_params
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/engine/base.py", line 927, in _execute_context
context)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/engine/base.py", line 1079, in _handle_dbapi_exception
util.reraise(*exc_info)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/engine/base.py", line 920, in _execute_context
context)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/SQLAlchemy-0.9.3-py2.7-linux-x86_64.egg/sqlalchemy/engine/default.py", line 425, in do_execute
cursor.execute(statement, parameters)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/PyMySQL-0.6.1-py2.7.egg/pymysql/cursors.py", line 93, in execute
escaped_args = tuple(conn.escape(arg) for arg in args)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/PyMySQL-0.6.1-py2.7.egg/pymysql/cursors.py", line 93, in <genexpr>
escaped_args = tuple(conn.escape(arg) for arg in args)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/PyMySQL-0.6.1-py2.7.egg/pymysql/connections.py", line 698, in escape
return escape_item(obj, self.charset)
File "/home/roman/Critical_ID/big_data/lib/python2.7/site-packages/PyMySQL-0.6.1-py2.7.egg/pymysql/converters.py", line 24, in escape_item
encoder = encoders[type(val)]
KeyError: <class 'pyramidapp.models.DataSource'>
答案 0 :(得分:0)
如果你从追溯的最后开始并走几行,你会发现PyMySQL lib中的错误是在它试图逃避该值时引发的 - 据说它有某种类型的dict被调用encoders
,其中包含编码器的映射。如果pyramidapp.models.DataSource
类传递了一个实例,它看起来就会失败。
当然,PyMySQL对SQLAlchemy声明性类一无所知,只能转义基本类型(整数,字符串等)。所以它甚至意外地看到了DataSource实例。
从您的代码示例中不太清楚导致问题的原因,但我最好的猜测是您要么将类实例分配给应该保存原始值的属性,要么使用类实例需要原始值的查询。像这样:
ds = DataSource(...)
other_ds.parent_id = ds # instead of .parent
或
session.query(DataSource).filter(DataSource.parent_id==ds)
实际上,这是:
lDS = list(oDS.filter_by(name=name).filter_by(parent=parent))