plone.app.relations 项目的 Zope 3 模式。
项目描述
内容
此扩展的目的是为克隆关系提供 Zope 3 模式。这已经用 Plone 2.5 和 Plone 3 进行了测试。
接口定义
一个新领域:
>>> from infrae.plone.relations.schema import PloneRelation
一个带有字段的简单界面:
>>> from zope.interface import Interface, implements >>> class IContent(Interface): ... """Sample interface.""" ... relation = PloneRelation(relation="my relation")
我可以从界面获取字段:
>>> r_field = IContent.get('relation')
这是一个领域:
>>> from zope.interface.verify import verifyObject >>> from zope.schema.interfaces import IField >>> verifyObject(IField, r_field) True
现在,查找反向关系的字段:
>>> class IBackContent(Interface): ... """Sample interface.""" ... relation = PloneRelation(relation="my relation", ... reverse=True)
为测试目的创建一个简单的内容
还有一个简单的实现:
>>> from OFS.Folder import Folder >>> class BaseContent(Folder): ... def __init__(self, id): ... super(BaseContent, self).__init__() ... self.id = id ... def UID(self): ... return 'uid-%s' % self.id
UID 由上下文工厂使用。
标准基类:
>>> class MyContent(BaseContent): ... implements(IContent)
和:
>>> class MyBackContent(BaseContent): ... implements(IBackContent)
现在,创建一些项目:
>>> for id in range(1, 5):
... name = 'it%d' % id
... item = MyContent(name)
... self.portal._setObject(name, item)
'it1'
'it2'
'it3'
'it4'
>>> it1 = self.portal.it1
>>> it2 = self.portal.it2
>>> it3 = self.portal.it3
>>> it4 = self.portal.it4
>>> itb1 = MyBackContent('itb1')
>>> self.portal._setObject('itb1', itb1)
'itb1'
>>> itb1 = self.portal.itb1
显示关系的实用程序
显示关系的助手:
>>> def display(rels):
... for rel in rels:
... print "Objects: %s" % list(rel['objects'])
... if rel.has_key("context"):
... print "Context: %s" % rel['context']
... if not rels:
... print "Empty"
简单的现场使用
直接设置和反向访问
并尝试对数据进行一些验证。数据是一个字典列表,表示该字段的所有关系。在字典中:
objects:表示关系的对象列表;
context:可能是存储为关系上下文的对象。
例子:
>>> bad_relation1 = [{'bad': None},]
>>> r_field.validate(bad_relation1)
Traceback (most recent call last):
...
ValidationError: Invalid structure
>>> good_relation = [{'objects': [it2, itb1]},]
>>> r_field.validate(good_relation)
并设置字段:
>>> r_field.set(it1, good_relation)
并从现场获取数据:
>>> relation = r_field.get(it1)
>>> relation
[{'objects': <plone.relations.relationships.IntIdSubObjectWrapper object at ...>}]
>>> display(relation)
Objects: [<MyContent at /plone/it2>, <MyBackContent at /plone/itb1>]
现在,我们可以从itb1内容中询问,它有一个反向字段:
>>> rb_field = IBackContent.get('relation')
>>> relation = rb_field.get(itb1)
>>> relation
[{'objects': <plone.relations.relationships.IntIdSubObjectWrapper object at ...>}]
>>> display(relation)
Objects: [<MyContent at /plone/it1>]
我们更新关系:
>>> good_relation = [{'objects': [it2, it3]},]
>>> r_field.set(it1, good_relation)
所以变化体现在:
>>> display(r_field.get(it1)) Objects: [<MyContent at /plone/it2>, <MyContent at /plone/it3>]
并且在反向字段中没有更多的关系:
>>> rb_field = IBackContent.get('relation')
>>> rb_field.get(itb1)
[]
现在,在反向字段上设置:
>>> good_relation = [{'objects': [it1, it2]}]
>>> rb_field.set(itb1, good_relation)
>>> display(rb_field.get(itb1))
Objects: [<MyContent at /plone/it1>, <MyContent at /plone/it2>]
在正常情况下:
>>> display(r_field.get(it1)) Objects: [<MyContent at /plone/it2>, <MyContent at /plone/it3>] 对象:[<MyBackContent at /plone/itb1>]
删除
您可以通过将关系设置为空列表[]来删除值:
>>> display(r_field.get(it2)) Objects: [<MyBackContent at /plone/itb1>] >>> r_field.set(it2, []) >>> display(r_field.get(it2)) Empty >>> display(rb_field.get(itb1)) Objects: [<MyContent at /plone/it1>]
和:
>>> display(r_field.get(it1)) Objects: [<MyContent at /plone/it2>, <MyContent at /plone/it3>] 对象:[<MyBackContent at /plone/itb1>] >>> r_field.set(it1, []) >>> 显示(r_field.get(it1)) 空的 >>> 显示(rb_field.get(itb1)) 空的
场独立性
另一种关系模式:
>>> class IComplexContent(Interface): ... """A content with two relation.""" ... relation1 = PloneRelation(relation="relation1") ... relation2 = PloneRelation(relation="relation2")
以及相关内容:
>>> class MyComplexContent(BaseContent): ... implements(IComplexContent)
像这样创建三个对象:
>>> itcx1 = MyComplexContent("itcx1")
>>> self.portal._setObject("itcx1", itcx1)
'itcx1'
>>> itcx1 = self.portal.itcx1
>>> itcx2 = MyComplexContent("itcx2")
>>> self.portal._setObject("itcx2", itcx2)
'itcx2'
>>> itcx2 = self.portal.itcx2
>>> itcx3 = MyComplexContent("itcx3")
>>> self.portal._setObject("itcx3", itcx3)
'itcx3'
>>> itcx3 = self.portal.itcx3
现在,添加关系:
>>> r1_field = IComplexContent.get("relation1")
>>> r1_field.set(itcx1, [{'objects': [itcx2,]}])
>>> display(r1_field.get(itcx1))
Objects: [<MyComplexContent at /plone/itcx2>]
>>> r2_field = IComplexContent.get("relation2")
>>> r2_field.set(itcx1, [{'objects': [itcx3,]}])
>>> display(r2_field.get(itcx1))
Objects: [<MyComplexContent at /plone/itcx3>]
并删除一个:
>>> r2_field.set(itcx1, []) >>> display(r2_field.get(itcx1)) Empty >>> display(r1_field.get(itcx1)) Objects: [<MyComplexContent at /plone/itcx2>]
更多约束
现在,您必须给出至少 1 个值,并且不超过 3 个:
>>> class ILengthContent(Interface): ... """Sample interface with length control.""" ... relation = PloneRelation(relation="my relation", ... min_length=1, ... max_length=3)
该字段实现IMinMaxLen:
>>> from zope.schema.interfaces import IMinMaxLen
>>> rl_field = ILengthContent.get('relation')
>>> verifyObject(IMinMaxLen, rl_field)
True
好的,现在一些不好的尝试:
>>> bad_relation = []
>>> rl_field.validate(bad_relation)
Traceback (most recent call last):
...
TooSmall: Less than 1 values
>>> bad_relation = [{'objects': [it2,]},
... {'objects': [it3,]},
... {'objects': [it4,]},
... {'objects': [itb1,]},]
>>> rl_field.validate(bad_relation)
Traceback (most recent call last):
...
TooBig: More than 3 values
现在,一个正确的:
>>> good_relation = [{'objects': [it2,]},]
>>> rl_field.validate(good_relation)
但我们也希望在关系中有唯一的对象:
>>> class IUniqueContent(Interface):
... """Sample interface only one item per relation."""
... relation = PloneRelation(relation="my relation",
... unique=True)
>>> ru_field = IUniqueContent.get('relation')
现在尝试一些:
>>> bad_relation = [{'objects': [it2, it3,]}]
>>> ru_field.validate(bad_relation)
Traceback (most recent call last):
...
ValidationError: Not uniques values in relation
>>> good_relation = [{'objects': [it2,]}]
>>> ru_field.validate(good_relation)
我们希望关系中的每个对象都实现一个特定的接口:
>>> class IConstraintContent(Interface):
... """Sample interface with constraint on relation."""
... relation = PloneRelation(relation="my relation",
... relation_schema=IUniqueContent)
>>> rs_field = IConstraintContent.get('relation')
使用上下文对象
两个接口可让您使用上下文对象:
>>> from infrae.plone.relations.schema import IPloneRelationContext >>> from infrae.plone.relations.schema import IPloneRelationContextFactory
这两个下一个导入是助手,但您可以使用它们,因为它是好的内容开始:
>>> from infrae.plone.relations.schema import BasePloneRelationContext >>> from infrae.plone.relations.schema import BasePloneRelationContextFactory
以下上下文接口:
>>> class IContextObject(IPloneRelationContext): ... """Simple context object."""
及其对应的对象:
>>> class MyContextObject(BasePloneRelationContext): ... implements(IContextObject)
我们将像这样声明该字段:
>>> class IContentWithContext(Interface): ... """Simple content with a context.""" ... relation = PloneRelation(relation="context relation", ... context_schema=IContextObject)
我们想要一个具有这种模式的对象:
>>> class MyContentWithContext(BaseContent): ... implements(IContentWithContext)
创建对象:
>>> itc1 = MyContentWithContext('itc1')
>>> self.portal._setObject('itc1', itc1)
'itc1'
>>> itc1 = self.portal.itc1
准备一个上下文对象:
>>> ctxt_fac = BasePloneRelationContextFactory(MyContextObject, IContextObject) >>> verifyObject(IPloneRelationContextFactory, ctxt_fac) True >>> ctxt1 = ctxt_fac(itc1, it1, dict()) >>> ctxt1 <MyContextObject at /plone/itc1/uid-it1> >>> verifyObject(IContextObject, ctxt1) True
获取字段:
>>> rc_field = IContentWithContext.get('relation')
现在我们可以试试这个关系:
>>> bad_relation = [{'objects': [it2, itb1,], 'context': it3,}]
>>> rc_field.validate(bad_relation)
Traceback (most recent call last):
...
ValidationError: Invalid context
>>> good_relation = [{'objects': [it2, itb1,], 'context': ctxt1,}]
>>> rc_field.validate(good_relation)
>>> rc_field.set(itc1, good_relation)
如果我们咨询关系:
>>> display(rc_field.get(itc1)) Objects: [<MyContent at /plone/it2>, <MyBackContent at /plone/itb1>] Context: <MyContextObject at uid-it1>
多对多关系接口
这个接口提供了一种比plone.app.relations提供的更通用的编辑关系的方法,让 Zope 3 模式以两种方式工作(对关系的正常访问和反向访问)。
创建简单的内容:
>>> from OFS.SimpleItem import SimpleItem >>> class BaseContent(SimpleItem): ... def __init__(self, id): ... super(BaseContent, self).__init__() ... self.id = id >>> for num in range(1, 20): ... id = 'it%02d' % num ... it = BaseContent(id) ... _ = self.portal._setObject(id, it) >>> self.portal.it01 <BaseContent at /plone/it01>
内容必须是IPersistent:
>>> from persistent import IPersistent >>> from zope.interface.verify import verifyObject >>> verifyObject(IPersistent, self.portal.it01) True
接口简单测试
我们有一个新的适配器来处理您的关系:
>>> from infrae.plone.relations.schema import IManyToManyRelationship >>> manager = IManyToManyRelationship(self.portal.it01) >>> verifyObject(IManyToManyRelationship, manager) True
好的,尝试添加关系:
>>> rel = manager.createRelationship((self.portal.it11, self.portal.it12,), ... sources=(self.portal.it02,), ... relation='test') >>> list(rel.sources) [<BaseContent at /plone/it01>, <BaseContent at /plone/it02>] >>> list(rel.targets) [<BaseContent at /plone/it11>, <BaseContent at /plone/it12>]
现在,我们可以检索关系列表:
>>> list(manager.getRelationships()) [<Relationship 'test' from (<BaseContent at /plone/it01>, <BaseContent at /plone/it02>) to (<BaseContent at /plone/it11>, <BaseContent at /plone/it12>)>]
方向
您可以使用setDirection方法反转关系的工作 方式:
>>> rel = manager.createRelationship(self.portal.it05, relation='reverse') >>> list(rel.targets) [<BaseContent at /plone/it05>] >>> manager.setDirection(False) >>> rel = manager.createRelationship(self.portal.it04, relation='reverse') >>> list(rel.targets) [<BaseContent at /plone/it01>]
您还具有搜索的传递性:
>>> manager = IManyToManyRelationship(self.portal.it04) >>> list(manager.getRelationshipChains(relation='reverse', ... target=self.portal.it05, ... maxDepth=2)) [(<Relationship 'reverse' from (<BaseContent at /plone/it04>,) to (<BaseContent at /plone/it01>,)>, <Relationship 'reverse' from (<BaseContent at /plone/it01>,) to (<BaseContent at /plone/it05>,)>)]
但是从源到目标总是遵循关系。因此,如果我们反向搜索,我们将找不到结果:
>>> manager.setDirection(False) >>> list(manager.getRelationshipChains(relation='reverse', ... target=self.portal.it05, ... maxDepth=2)) []
方向只是改变关系对象上源或目标的含义。它不会改变关系本身。
具有传递性的更大示例
收回第一个测试,并添加一个套件:
>>> manager = IManyToManyRelationship(self.portal.it16) >>> manager.setDirection(False) >>> rel = manager.createRelationship((self.portal.it12, self.portal.it14), ... relation='test') >>> manager.setDirection(True) >>> rel = manager.createRelationship((self.portal.it17, self.portal.it18), ... sources=(self.portal.it19,), ... relation='test')
新链尝试:
>>> manager = IManyToManyRelationship(self.portal.it02) >>> list(manager.getRelationshipChains(relation='test', ... target=self.portal.it18, ... maxDepth=3)) [(<Relationship 'test' from (<BaseContent at /plone/it01>, <BaseContent at /plone/it02>) to (<BaseContent at /plone/it11>, <BaseContent at /plone/it12>)>, <Relationship 'test' from (<BaseContent at /plone/it12>, <BaseContent at /plone/it14>) to (<BaseContent at /plone/it16>,)>, <Relationship 'test' from (<BaseContent at /plone/it16>, <BaseContent at /plone/it19>) to (<BaseContent at /plone/it17>, <BaseContent at /plone/it18>)>)]
存取器
getTargets返回与给定对象作为源的关系的对象的惰性列表, getSources返回与给定对象作为目标的关系的对象的惰性列表:
>>> manager = IManyToManyRelationship(self.portal.it16) >>> list(manager.getTargets()) [<BaseContent at /plone/it17>, <BaseContent at /plone/it18>] >>> list(manager.getSources()) [<BaseContent at /plone/it12>, <BaseContent at /plone/it14>]
如果我们反转方向:
>>> manager.setDirection(False) >>> list(manager.getTargets()) [<BaseContent at /plone/it12>, <BaseContent at /plone/it14>] >>> list(manager.getSources()) [<BaseContent at /plone/it17>, <BaseContent at /plone/it18>]
删除
删除关系:
>>> manager.setDirection(True) >>> manager.deleteRelationship() >>> list(manager.getRelationships()) [] >>> manager = IManyToManyRelationship(self.portal.it19) >>> list(manager.getRelationships()) [<Relationship 'test' from (<BaseContent at /plone/it19>,) to (<BaseContent at /plone/it17>, <BaseContent at /plone/it18>)>] >>> manager.deleteRelationship(target=self.portal.it17) >>> list(manager.getRelationships()) [<Relationship 'test' from (<BaseContent at /plone/it19>,) to (<BaseContent at /plone/it18>,)>] >>> manager.deleteRelationship() >>> list(manager.getRelationships()) [] >>> manager = IManyToManyRelationship(self.portal.it01) >>> manager.deleteRelationship(remove_all_sources=True, multiple=True) >>> manager = IManyToManyRelationship(self.portal.it02) >>> list(manager.getRelationships()) []
变化
1.0
第一次发布。
学分
由比利时佛兰德政府提供支持,用于应用程序 < http://www.zonderisgezonder.be >。
项目详情
下载文件
下载适用于您平台的文件。如果您不确定要选择哪个,请了解有关安装包的更多信息。
源分布
内置分布
infrae.plone.relations.schema -1.0.tar.gz 的哈希值
| 算法 | 哈希摘要 | |
|---|---|---|
| SHA256 | 3c9358eaa8bd8df4bda42006b2aa48af81b1cce723d27120efe63f94284f5c94 |
|
| MD5 | b14edb57938ba3c42c479dc1ccb116b1 |
|
| 布莱克2-256 | caee4b094160bb2362f9923280ac989a64efa65af87dd76cdd36d4bdea76e27f |
infrae.plone.relations.schema -1.0-py2.4.egg 的哈希值
| 算法 | 哈希摘要 | |
|---|---|---|
| SHA256 | 7854dd0a898dab9fc1e404072f3519ff4e7508bca4ed912b9105287bfeb044eb |
|
| MD5 | c6d436d41a8191e2ae485b3528e8b207 |
|
| 布莱克2-256 | 065938fde1c3efa6c101e2ef9a9c2105456cfc6385f4712510703474c0d4af9f |