spyne多对多版本的server_sqlalchemy

时间:2015-12-01 15:56:10

标签: spyne

我修改了server_sqlalchemy示例以启用多表,如下所示BlogPost并添加了与permissions = Array(Permission).store_as(table(multi=True))类似的方法get_permissionput_permissionget_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表中吗?如果没有,如何实现客户端所示的期望行为?

由于

1 个答案:

答案 0 :(得分:0)

TL; DR:使用本文底部的第一个建议的解决方法。

好的,我知道这是一个问题。

以下是这里发生的事情:

  1. 您成功插入两个权限对象,获取其服务器生成的ID。
  2. 您创建一个用户对象并将新插入的权限放在User实例的权限数组中。
  3. 当put_user作为使用新会话的单独请求进入时,sqlalchemy不记得这两个权限对象已经在数据库中并尝试再次插入它们。
  4. 由于已存在这些权限的主键,因此会出现该错误。
  5. 因此,它与权限数组中的multi=True无关。

    默认情况下,SQLAlchemy中的关系是“所有者”关系。在这里,您需要一个“用户”关系。

    即。在这种情况下,User实例不拥有“拥有”权限,只是“使用”它们。例如,删除用户时不需要删除任何权限。

    我不知道如何定义与SQLAlchemy的“用户”关系。您需要将“已使用”对象引入会话,并且这样做的唯一方法是选择它们 - 这是低效的。以下是SQLAlchemy的作者对此主题的回答:https://stackoverflow.com/a/9674552/1520211

    从2.12开始,Spyne不支持将关系标记为“所有者/用户”关系 - 我只是没有时间研究SQLAlchemy内部,足以提出一个优雅的实现。

    所以我得到了两个解决方法:

    1. user.permissions = [session.query(Permission).filter_by(id=perm.id).one() for perm in user.permissions]

      非常低效,但是单线。为每个传入的权限对象运行一个select。因为它使用.one(),所以它将确保客户端只能添加已有的权限。请注意,Spyne将优雅地处理NotFoundException并返回客户端错误。

    2. 手动插入关系行的高效版本。

      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” ”

    3. 如果您愿意,可以加入http://lists.spyne.io/listinfo/people进行进一步讨论。