使用 SqlSoup 处理数据库视图时出错
我想用SqlSoup来处理一个已经存在的数据库,这个数据库里有视图。访问一个表的时候一切都很顺利,但当我尝试访问一个视图时,就出现了“PKNotFoundError: 表 '[viewname]' 没有定义主键...”这样的错误。
我是不是可以理解为SqlSoup默认情况下不支持数据库视图呢?我在谷歌、StackOverflow或者SqlAlchemy的邮件列表上都找不到相关的信息。如果你遇到这个问题,想要访问那些不能更新的视图,你会怎么做?我对SQLAlchemy和SQLSoup还很陌生。
这里有一个具体的例子:
from sqlalchemy.ext.sqlsoup import SqlSoup
u = SqlSoup('postgresql+psycopg2://PUBLIC@unison-db.org:5432/unison')
seq = u.pseq.filter(u.pseq.pseq_id==76).all() # okay
aliases = u.pseqalias.filter(u.pseqalias.pseq_id==76).all()
这是一个公共数据库。你可以使用psql运行等效的查询:
psql -h unison-db.org -U PUBLIC -d unison -c 'select * from pseq where pseq_id=76'
psql -h unison-db.org -U PUBLIC -d unison -c 'select * from pseqalias where pseq_id=76'
3 个回答
像这样(没测试过):
from sqlalchemy import sql
from sqlalchemy.ext.sqlsoup import SqlSoup
u = SqlSoup('postgresql+psycopg2://PUBLIC@unison-db.org:5432/unison')
pseq_id = sql.column('pseq_id')
aliases = u.bind.execute(sql.select([pseq_id, '*'], from_obj=['pseqalias'])\
.where(pseq_id==76)).fetchall()
当然你也可以这样做:
aliases = u.bind.execute('select * from pseqalias where pseq_id=76').fetchall()
...但这样的话,你就失去了可重用性。
来自Michael Bayer的内容:
你需要把作为主键的列传递给底层的映射器,使用sqlsoup.map_to()方法。不过,目前没有一个简单的接口可以做到这一点,因为你还需要Table对象来获取这些列。所以在这个接口改进之前,现在的做法看起来是这样的:
metadata = u._metadata t = Table("pseqaliases", metadata, autoload=True)
u.map_to("pseqaliases", selectable=t, mapper_args={"primary_key":[t.c.col1, t.c.col2]})
这里的"primary_key"参数就是传给映射器的,关于这个的例子可以在http://www.sqlalchemy.org/docs/orm/mapper_config.html的顶部找到。
http://groups.google.com/group/sqlalchemy/browse_thread/thread/fc1e8d079e10bac8
我尝试了map_to()方法,但仍然收到了主键错误。不过,下面的方法却能正常工作:
ss = SqlSoup(db.engine)
meta = ss._metadata
tbl_vrmf = sa.Table("vRMF", meta, autoload=True)
vrmf_pks = [tbl_vrmf.c.dateId, tbl_vrmf.c.ident, tbl_vrmf.c.mnum]
vrmf = ss.map(tbl_vrmf, primary_key=vrmf_pks)
感谢Randy提供的map()提示。这是一个完整的解决方案,你可以直接尝试(数据库是公开的):
from sqlalchemy.ext.sqlsoup import SqlSoup
from sqlalchemy import Table
u = SqlSoup('postgresql+psycopg2://PUBLIC@unison-db.org:5432/unison')
pa_t = Table("palias", u._metadata, autoload=True, schema='unison')
pa = u.map(pa_t,primary_key=[pa_t.c.pannotation_id])
pa.slice(0,20).all()
这个例子使用的是Python 2.7.1和Alchemy 0.7.2。
如果需要参考资料,可以查看: