Skip to main content

plone.app.relations 项目的 Zope 3 模式。

项目描述

<nav class="contents" id="contents" role="doc-toc">

内容

</nav>

此扩展的目的是为克隆关系提供 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 (12.5 kB 查看哈希

已上传 source

内置分布

infrae.plone.relations.schema-1.0-py2.4.egg (28.5 kB 查看哈希

已上传 2 4