我想要做以下事情,定義兩個實例互相引用的類,如以下示例中的用戶和組。用戶可以屬於多個組,並且一個組可以包含多個用戶。實際的數據存儲在數據庫中,並且使用外鍵是一個簡單的多對多關係。沒有問題。使用zope.schema定義循環引用
之後,數據通過ORM加載並存儲在python對象的實例中。由於使用的ORM(SQLAlchemy)管理backrefs,所以仍然沒有問題。
現在我想檢查一下python對象是否符合使用zope.interface和zope.schema的某個接口。這是我陷入困境的地方。
import zope.schema as schema
from zope.interface import Interface, implements
class IGroup(Interface):
name = schema.TextLine(title=u"Group's name")
# user_list = schema.List(title = u"List of Users in this group", value_type = sz.Object(IUser))
class IUser(Interface):
name = schema.TextLine(title=u"User's name")
group_list = schema.List(title = u"List of Groups containing that user",
value_type = schema.Object(IGroup))
IGroup._InterfaceClass__attrs['user_list'] = zs.List(title = u"List of Users in this group", required = False, value_type = zs.Object(IUser))
class Group(object):
implements(IGroup)
def __init__(self, name):
self.name = name
self.user_list = []
class User(object):
implements(IUser)
def __init__(self, name):
self.name = name
self.group_list = []
alice = User(u'Alice')
bob = User(u'Bob')
chuck = User(u'Chuck')
group_users = Group(u"Users")
group_auditors = Group(u"Auditors")
group_administrators = Group(u"Administrators")
def add_user_in_group(user, group):
user.group_list.append(group)
group.user_list.append(user)
add_user_in_group(alice, group_users)
add_user_in_group(bob, group_users)
add_user_in_group(chuck, group_users)
add_user_in_group(chuck, group_auditors)
add_user_in_group(chuck, group_administrators)
for x in [alice, bob, chuck]:
errors = schema.getValidationErrors(IUser, x)
if errors: print errors
print "User ", x.name, " is in groups ", [y.name for y in x.group_list]
for x in [group_users, group_auditors, group_administrators]:
errors = schema.getValidationErrors(IGroup, x)
if errors: print errors
print "Group ", x.name, " contains users ", [y.name for y in x.user_list]
我的問題是註釋行。我無法使用IUser定義IGroup,因爲那時IUser尚未定義。我已經找到了一個解決方法,在IUser的定義完成之後完成IGroup的定義,但根本不令人滿意,因爲IUser和IGroup是在不同的源文件中定義的,部分IGroup是在定義IUser的文件中定義的。
是否有任何正確的方法來做到這一點使用zope.schema?
正如我在評論中所說的,我不相信Martijn的答案真的可行(而我的解決方法肯定無效)。我不確定你的。理由:根據我的理解,IBar是在定義時使用IFoo字段的副本定義的,因此,在更改IFoo後,我不會更改嵌入的IFoo。然而,我並不確定... – kriss 2012-02-24 03:22:11
是的,在Python中,原始類在這裏是猴子補丁,所以在導入接口模塊後,運行期間任何時候IFoo的所有使用者都將擁有一個具有正確綁定的對象字段用於驗證和內省的模式。這項技術已被用於多個生產項目並取得一致的成功。 – sdupton 2012-02-24 07:05:50