server_sqlalchemy 的 spyne 多对多版本
spyne many-to-many version of server_sqlalchemy
我修改了 server_sqlalchemy 示例以启用 multi table 如下 permissions = Array(Permission).store_as(table(multi=True))
并添加了类似 get_permission
、put_permission
和 get_all_permission
的方法get_user
、put_user
和 get_all_user
.
在客户端,我使用如下的 suds 客户端:
from suds.client import Client
c = Client('http://localhost:8000/?wsdl')
#create two permissions
p = c.factory.create('Permission')
p.application = 'usermgr'
p.operation = 'modify'
p.id = c.service.put_permission(p)
q = c.factory.create('Permission')
q.application = 'accountmgr'
q.operation = 'read'
q.id = c.service.put_permission(q)
#create two users
u = c.factory.create('User')
u.user_name = 'abcd'
u.full_name = 'abcd xyz'
u.email = 'abcd@xyz.com'
u.permissions = c.factory.create('PermissionArray')
u.permissions.Permission = [p,q]
u.id = c.service.put_user(u)
v = c.factory.create('User')
v.user_name = 'dcba'
v.full_name = 'dcba zyx'
v.email = 'dcba@zyx.com'
v.permissions = c.factory.create('PermissionArray')
v.permissions.Permission = [p,q] #note the same p,q used in u
v.id = c.service.put_user(v)
put_user(v)
由于
而失败
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) UNIQUE constraint failed: permission.id [SQL: 'INSERT INTO permission (id, operation, application) VALUES (?, ?, ?)'] [parameters: ((3, 'modify', 'usermgr'), (4, 'read', 'accountmgr'))]
很明显,代码试图将 p,q gain 插入权限 table 但失败了。 multi table 不应该只插入 user_permissions table 吗?如果没有,我如何实现客户端中显示的所需行为?
谢谢
TL;DR:使用此 post 底部建议的第一个解决方法。
好的,我知道这会是个问题。
这是这里发生的事情:
- 您成功插入了两个权限对象,获取了它们的服务器生成的id。
- 您创建一个用户对象并将新插入的权限放入用户实例的权限数组中。
- 由于 put_user 作为使用新会话的单独请求进入,sqlalchemy 不记得这两个权限对象已经在数据库中并尝试再次插入它们。
- 由于这些权限的主键已经存在,您会收到该错误。
所以这与在权限数组中包含 multi=True
无关。
SQLAlchemy 中的关系默认为 "owner" 关系。这里你需要一个 "user" 关系。
即在这种情况下,User
实例没有 "own" 权限,它们只是 "use" 权限。例如删除用户时需要删除none的权限
我不知道用 SQLAlchemy 定义 "user" 关系的任何方法。您需要将 "used" 对象放入会话中,唯一的方法是 selecting 它们——这是低效的。这是 SQLAlchemy 的作者关于这个主题的回答:
从 2.12 开始,Spyne 还不支持将关系标记为 "owner/user" 关系——我只是没有足够的时间研究 SQLAlchemy 的内部机制来提出一个优雅的实现。
所以我为您准备了两个解决方法:
user.permissions = [session.query(Permission).filter_by(id=perm.id).one()
for perm in user.permissions]
非常低效,但单行。为每个传入的权限对象运行 select。因为它使用 .one()
它将确保客户端只能添加已经存在的权限。请注意,Spyne 将优雅地处理 NotFoundException
和 return 客户端错误。
手动插入关系行的高效版本。
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)
请注意
我。这可以进一步优化以使用发出多行的单个插入。
二。如果权限 ID 无效,这将引发 Spyne 不知道的外键错误。这意味着客户端将收到服务器错误,并认为您这边有问题,而错误实际上是他的错。因此,如果您关心重新调整正确的异常,则需要捕获数据库异常,确保它是针对指向权限 table 的特定外键的约束验证,并引发一个客户端错误,说明类似以下内容"Unknown permission id".
如果您愿意,可以加入 http://lists.spyne.io/listinfo/people 进一步讨论。
我修改了 server_sqlalchemy 示例以启用 multi table 如下 permissions = Array(Permission).store_as(table(multi=True))
并添加了类似 get_permission
、put_permission
和 get_all_permission
的方法get_user
、put_user
和 get_all_user
.
在客户端,我使用如下的 suds 客户端:
from suds.client import Client
c = Client('http://localhost:8000/?wsdl')
#create two permissions
p = c.factory.create('Permission')
p.application = 'usermgr'
p.operation = 'modify'
p.id = c.service.put_permission(p)
q = c.factory.create('Permission')
q.application = 'accountmgr'
q.operation = 'read'
q.id = c.service.put_permission(q)
#create two users
u = c.factory.create('User')
u.user_name = 'abcd'
u.full_name = 'abcd xyz'
u.email = 'abcd@xyz.com'
u.permissions = c.factory.create('PermissionArray')
u.permissions.Permission = [p,q]
u.id = c.service.put_user(u)
v = c.factory.create('User')
v.user_name = 'dcba'
v.full_name = 'dcba zyx'
v.email = 'dcba@zyx.com'
v.permissions = c.factory.create('PermissionArray')
v.permissions.Permission = [p,q] #note the same p,q used in u
v.id = c.service.put_user(v)
put_user(v)
由于
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) UNIQUE constraint failed: permission.id [SQL: 'INSERT INTO permission (id, operation, application) VALUES (?, ?, ?)'] [parameters: ((3, 'modify', 'usermgr'), (4, 'read', 'accountmgr'))]
很明显,代码试图将 p,q gain 插入权限 table 但失败了。 multi table 不应该只插入 user_permissions table 吗?如果没有,我如何实现客户端中显示的所需行为?
谢谢
TL;DR:使用此 post 底部建议的第一个解决方法。
好的,我知道这会是个问题。
这是这里发生的事情:
- 您成功插入了两个权限对象,获取了它们的服务器生成的id。
- 您创建一个用户对象并将新插入的权限放入用户实例的权限数组中。
- 由于 put_user 作为使用新会话的单独请求进入,sqlalchemy 不记得这两个权限对象已经在数据库中并尝试再次插入它们。
- 由于这些权限的主键已经存在,您会收到该错误。
所以这与在权限数组中包含 multi=True
无关。
SQLAlchemy 中的关系默认为 "owner" 关系。这里你需要一个 "user" 关系。
即在这种情况下,User
实例没有 "own" 权限,它们只是 "use" 权限。例如删除用户时需要删除none的权限
我不知道用 SQLAlchemy 定义 "user" 关系的任何方法。您需要将 "used" 对象放入会话中,唯一的方法是 selecting 它们——这是低效的。这是 SQLAlchemy 的作者关于这个主题的回答:
从 2.12 开始,Spyne 还不支持将关系标记为 "owner/user" 关系——我只是没有足够的时间研究 SQLAlchemy 的内部机制来提出一个优雅的实现。
所以我为您准备了两个解决方法:
user.permissions = [session.query(Permission).filter_by(id=perm.id).one() for perm in user.permissions]
非常低效,但单行。为每个传入的权限对象运行 select。因为它使用
.one()
它将确保客户端只能添加已经存在的权限。请注意,Spyne 将优雅地处理NotFoundException
和 return 客户端错误。手动插入关系行的高效版本。
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)
请注意
我。这可以进一步优化以使用发出多行的单个插入。
二。如果权限 ID 无效,这将引发 Spyne 不知道的外键错误。这意味着客户端将收到服务器错误,并认为您这边有问题,而错误实际上是他的错。因此,如果您关心重新调整正确的异常,则需要捕获数据库异常,确保它是针对指向权限 table 的特定外键的约束验证,并引发一个客户端错误,说明类似以下内容"Unknown permission id".
如果您愿意,可以加入 http://lists.spyne.io/listinfo/people 进一步讨论。