我修改了server_sqlalchemy示例以启用多表,如下所示BlogPost
并添加了与permissions = Array(Permission).store_as(table(multi=True))
类似的方法get_permission
,put_permission
和get_all_permission
,{{1 }和get_user
。
在客户端,我使用的是suds客户端,如下所示:
put_user
get_all_user
由于
sqlalchemy.exc.InvalidRequestError:由于在刷新期间发生了先前的异常,此会话的事务已回滚。要使用此Session开始新事务,请首先发出Session.rollback()。原始异常是:(sqlite3.IntegrityError)UNIQUE约束失败:permission.id [SQL:'INSERT INTO权限(id,操作,应用程序)VALUES(?,?,?)'] [参数:((3,'修改' ,'usermgr'),(4,'read','accountmgr'))]
显然,代码试图将p,q gain插入权限表并失败。不应该只将多表插入到user_permissions表中吗?如果没有,如何实现客户端所示的期望行为?
由于
答案 0 :(得分:0)
TL; DR:使用本文底部的第一个建议的解决方法。
好的,我知道这是一个问题。
以下是这里发生的事情:
因此,它与权限数组中的multi=True
无关。
默认情况下,SQLAlchemy中的关系是“所有者”关系。在这里,您需要一个“用户”关系。
即。在这种情况下,User
实例不拥有“拥有”权限,只是“使用”它们。例如,删除用户时不需要删除任何权限。
我不知道如何定义与SQLAlchemy的“用户”关系。您需要将“已使用”对象引入会话,并且这样做的唯一方法是选择它们 - 这是低效的。以下是SQLAlchemy的作者对此主题的回答:https://stackoverflow.com/a/9674552/1520211
从2.12开始,Spyne不支持将关系标记为“所有者/用户”关系 - 我只是没有时间研究SQLAlchemy内部,足以提出一个优雅的实现。
所以我得到了两个解决方法:
user.permissions = [session.query(Permission).filter_by(id=perm.id).one()
for perm in user.permissions]
非常低效,但是单线。为每个传入的权限对象运行一个select。因为它使用.one()
,所以它将确保客户端只能添加已有的权限。请注意,Spyne将优雅地处理NotFoundException
并返回客户端错误。
手动插入关系行的高效版本。
permissions = user.permissions
user.permissions = []
session.add(user)
session.flush()
for perm in permissions:
session.connection().execute("insert into user_permission "
"(user_id, permission_id) values (%s, %s)",
perm.id, user.id)
请注意
我。这可以进一步优化,以便使用多行发出单个插入。
II。如果权限id无效,则会抛出Spyne一无所知的外键错误。这意味着客户端将收到服务器错误并认为您身边存在问题,而错误实际上是他的错。因此,如果您关心重新调整正确的异常,则需要捕获数据库异常,确保它是指向权限表的特定外键的约束验证,并引发一个客户端错误,其中显示的内容为“未知权限ID” ”
如果您愿意,可以加入http://lists.spyne.io/listinfo/people进行进一步讨论。