Zope 3的标签引擎
项目描述
标签
标签引擎允许用户为任何类型的对象分配标签。标签是一个简单的字符串。
>>> from lovely import tag
标签引擎
标签引擎提供了操作和查询标记项的功能。
>>> engine = tag.TaggingEngine() >>> engine <TaggingEngine entries=0>
第一步是将标签与用户的项关联起来。项通过它们的 intId 进行引用,用户是一个系统范围内的唯一字符串,而标签是一个简单的字符串列表。
在更新引擎之前,我们需要确保持久化对象可以被适配到键引用
>>> import zope.component >>> from zope.app.keyreference import testing>>> zope.component.provideAdapter(testing.SimpleKeyReference)
而不是提供添加和更新标签的单独 API,这两个操作都是通过 update() 方法完成的。将其视为更新标签引擎。
>>> engine.update(1, u'srichter', [u'USA', u'personal']) >>> engine.update(2, u'srichter', [u'austria', u'lovely']) >>> engine.update(3, u'jodok', [u'Austria', u'personal']) >>> engine.update(2, u'jodok', [u'austria', u'lovely', u'work'])
接下来,您可以向引擎提出几个问题。
查询项
此方法允许查找项。例如,我们想要找到所有带有“个人”标签的项
>>> sorted(engine.getItems(tags=(u'personal',))) [1, 3]
注意:查询方法返回集合。
>>> type(engine.getItems()) <type 'set'>
此外,您还可以查询特定用户的所有项
>>> sorted(engine.getItems(users=(u'srichter',))) [1, 2] >>> sorted(engine.getItems(users=(u'srichter', u'jodok'))) [1, 2, 3]
最后,您可以将标签和用户指定组合起来
>>> sorted(engine.getItems( ... tags=(u'personal',), users=(u'srichter', u'jodok'))) [1, 3]
您还可以不指定标签或用户来查询所有项
>>> sorted(engine.getItems()) [1, 2, 3]
查询用户
与上述两种方法类似,您可以查询用户。首先,我们正在寻找指定特定标签的所有用户。
>>> sorted(engine.getUsers(tags=(u'personal',))) [u'jodok', u'srichter'] >>> sorted(engine.getUsers(tags=(u'Austria',))) [u'jodok']
注意:查询方法返回集合。
>>> type(engine.getUsers()) <type 'set'>
接下来,您也可以找到由用户标记的所有项
>>> sorted(engine.getUsers(items=(1,))) [u'srichter'] >>> sorted(engine.getUsers(items=(2,))) [u'jodok', u'srichter']
与之前一样,您可以将这两个标准组合起来
>>> sorted(engine.getUsers(tags=(u'USA',), items=(1,))) [u'srichter'] >>> sorted(engine.getUsers(tags=(u'personal',), items=(1, 3))) [u'jodok', u'srichter']
您还可以不指定标签或项来查询所有用户
>>> sorted(engine.getUsers()) [u'jodok', u'srichter']
查询标签对象
有时直接获取实际的标签对象很有用。可以通过标签名称、用户和项查询这些标签对象。
>>> sorted(engine.getTagObjects(tags=(u'personal',))) [<Tag u'personal' for 1 by u'srichter'>, <Tag u'personal' for 3 by u'jodok'>] >>> sorted(engine.getTagObjects(tags=(u'personal',), ... users=(u'srichter',))) [<Tag u'personal' for 1 by u'srichter'>] >>> sorted(engine.getTagObjects(tags=(u'personal',), ... items=(3,))) [<Tag u'personal' for 3 by u'jodok'>]
我们还可以搜索
标签统计
>>> from lovely.tag.interfaces import ITaggingStatistics >>> ITaggingStatistics.providedBy(engine) True >>> engine.tagCount 6 >>> engine.itemCount 3 >>> engine.userCount 2
组合查询
由于这些查询方法返回集合,因此可以轻松地将它们组合
>>> users1 = engine.getUsers(items=(1,)) >>> users2 = engine.getUsers(items=(2,)) >>> sorted(users1.intersection(users2)) [u'srichter']
更改和删除条目
“srichter”已从美国迁至德国
>>> engine.update(1, u'srichter', [u'Germany', u'personal']) >>> sorted(engine.getTags(items=(1,), users=(u'srichter',))) [u'Germany', u'personal']
我们通过向 update 方法传递空列表来删除条目
>>> engine.update(1, u'srichter', []) >>> sorted(engine.getTags(items=(1,))) [] >>> sorted(engine.getTags()) [u'Austria', u'austria', u'lovely', u'personal', u'work'] >>> sorted(engine.getItems()) [2, 3]
现在让我们删除第二个项目的标签。我们想要确保“srichter”再也找不到
>>> engine.update(2, u'srichter', []) >>> sorted(engine.getUsers()) [u'jodok']
要全局删除条目,请使用下面描述的 delete 方法。
标签对象
在内部,标签引擎使用 Tag 类来存储有关特定项、用户和标签名称对的全部数据。
>>> from lovely.tag.tag import Tag
Tag 对象使用上述提到的三个信息初始化。
>>> sample = Tag(1, u'user', u'tag1') >>> sample <Tag u'tag1' for 1 by u'user'>
您也可以将这些三项视为标签的唯一键。除了这三个属性外,还指定了一个创建日期
>>> sample.item 1 >>> sample.user u'user' >>> sample.name u'tag1' >>> sample.timestamp datetime.datetime(...)
可标记的对象
从理论上讲,所有对象都可以被标记。但这可能并不理想。因此,对象必须提供ITaggable接口才能被标记。
>>> import zope.interface>>> class Image(object): ... zope.interface.implements(tag.interfaces.ITaggable) >>> image = Image()>>> class File(object): ... pass >>> file = File()
然后可以将可标记对象适配到ITagging接口。为了使其工作,我们必须注册适配器
>>> zope.component.provideAdapter(tag.Tagging)
在我们现在可以使用标记对象之前,我们需要将标记引擎以及整数ID生成器注册为工具
>>> zope.component.provideUtility(engine, tag.interfaces.ITaggingEngine)>>> from zope.app import intid >>> intIds = intid.IntIds() >>> zope.component.provideUtility(intIds, intid.interfaces.IIntIds)
将文件适配为标记对象应该失败
>>> tag.interfaces.ITagging(file) Traceback (most recent call last): ... TypeError: ('Could not adapt', <File ...>, <InterfaceClass ...ITagging>)
但图像可以被标记
>>> tagging = tag.interfaces.ITagging(image)
一开始图像没有标签
>>> sorted(tagging.getTags()) []
现在让“srichter”和“jodok”添加一些标签
>>> tagging.update(u'srichter', [u'home', u'USA']) >>> tagging.update(u'jodok', [u'vacation', u'USA'])>>> sorted(tagging.getTags()) [u'USA', u'home', u'vacation']
当然,你也可以通过“srichter”请求标签
>>> sorted(tagging.getTags(users=[u'srichter'])) [u'USA', u'home']
进一步,你可以请求查看所有标记了该图像的用户
>>> sorted(tagging.getUsers()) [u'jodok', u'srichter']
或所有指定了特定标签的用户
>>> sorted(tagging.getUsers(tags=(u'home',))) [u'srichter'] >>> sorted(tagging.getUsers(tags=(u'USA',))) [u'jodok', u'srichter']
使用命名标记引擎
>>> class INamedTagging(tag.interfaces.ITagging): ... pass >>> class NamedTagging(tag.Tagging): ... zope.interface.implements(INamedTagging) ... zope.component.adapts(tag.interfaces.ITaggable) ... engineName = 'IAmNamed' >>> zope.component.provideAdapter(NamedTagging, ... (tag.interfaces.ITaggable,), ... INamedTagging)>>> namedTagging = INamedTagging(image) >>> namedTagging.tags = ['named1', 'named2'] >>> namedTagging.update(u'jukart', [u'works', u'hard']) Traceback (most recent call last): ... ComponentLookupError: (<InterfaceClass lovely.tag.interfaces.ITaggingEngine>, 'IAmNamed')
我们还没有注册任何命名标记引擎。让我们看看如果我们用空标签列表更新会发生什么。
>>> namedTagging.update(u'jukart', [])
如果我们不添加标签就更新,这可能是因为一个对象已被删除。这通常在ObjectRemovedEvent的事件处理器中完成。如果我们在这种情况下引发异常,则无法删除站点。
现在我们注册一个命名标记引擎。
>>> namedEngine = tag.TaggingEngine() >>> zope.component.provideUtility(namedEngine, tag.interfaces.ITaggingEngine, ... name='IAmNamed')>>> namedTagging = INamedTagging(image) >>> namedTagging.tags = ['named1', 'named2'] >>> sorted(namedTagging.getTags()) [] >>> namedTagging.update(u'jukart', [u'works', u'hard']) >>> sorted(namedTagging.getTags()) [u'hard', u'works']
新标签不在未命名的标记引擎中。
>>> sorted(tagging.getTags()) [u'USA', u'home', u'vacation']
IUserTagging
还有一个适配器用于ITaggable对象,它提供了一个简单的标签属性,该属性接受当前主体为ITaggable定义的标签列表。
>>> zope.component.provideAdapter(tag.UserTagging) >>> userTagging = tag.interfaces.IUserTagging(image) >>> userTagging.tags Traceback (most recent call last): ... ValueError: User not found
我们得到一个ValueError,因为我们没有在这个测试中进行交互,因此实现无法找到主体。我们必须创建一个主体和参与。
>>> from zope.security.testing import Principal, Participation >>> from zope.security import management >>> p = Principal(u'srichter') >>> participation = Participation(p) >>> management.endInteraction() >>> management.newInteraction(participation) >>> sorted(userTagging.tags) [u'USA', u'home'] >>> userTagging.tags = [u'zope3', u'guru'] >>> sorted(userTagging.tags) [u'guru', u'zope3']
标签云
所有像Flickr、del.icio.us这样的门户网站都使用标记并生成标签云。标签云包含标签及其频率。
getCloud方法返回一组形式为(‘tag’,频率)的元组。它接受与getTags相同的参数。
>>> type(engine.getCloud()) <type 'set'>
现在让我们添加一些标签,以便稍后生成云。
>>> engine.update(3, u'michael', [u'Austria', u'Bizau']) >>> engine.update(2, u'michael', [u'lovely', u'USA']) >>> engine.update(1, u'jodok', [u'USA',])
最常见的情况是生成全局标签云。
>>> sorted(engine.getCloud()) [(u'Austria', 2), (u'Bizau', 1), (u'USA', 3), (u'austria', 1), (u'guru', 1), (u'lovely', 2), (u'personal', 1), (u'vacation', 1), (u'work', 1), (u'zope3', 1)]
当然,你可以基于项目生成云。你不能传递项目元组,只允许单个项目。
>>> sorted(engine.getCloud(items=[1])) [(u'USA', 1)]
这同样适用于按用户查询。
>>> sorted(engine.getCloud(users=[u'srichter'])) [(u'guru', 1), (u'zope3', 1)]
或更多用户和少量项目。
>>> sorted(engine.getCloud(items=[1, 2, 3], users=[u'srichter', u'jodok'])) [(u'Austria', 1), (u'USA', 1), (u'austria', 1), (u'lovely', 1), (u'personal', 1), (u'work', 1)]
对于同一用户的标签重新更新不会影响云的权重
>>> engine.update(1, u'jodok', [u'USA',]) >>> sorted(engine.getCloud(items=[1, 2, 3], users=[u'srichter', u'jodok'])) [(u'Austria', 1), (u'USA', 1), (u'austria', 1), (u'lovely', 1), (u'personal', 1), (u'work', 1)]
对于同一用户的标签重新更新不会影响云的权重
>>> engine.update(1, u'jodok', [u'USA',]) >>> sorted(engine.getCloud(items=[1, 2, 3], users=[u'srichter', u'jodok'])) [(u'Austria', 1), (u'USA', 1), (u'austria', 1), (u'lovely', 1), (u'personal', 1), (u'work', 1)]
删除标签对象
当对象从intids实用程序中注销时,它将从每个引擎中删除。让我们看看我们到目前为止有多少项目。
>>> len(engine.getItems()) 5 >>> len(namedEngine.getItems()) 1
我们可以使用标记引擎的delete方法通过定义用户、项目或标签名称来删除标签对象。
>>> u'austria' in engine.getTags() True >>> engine.delete(tag=u'austria') >>> u'austria' in engine.getTags() False
如果我们为用户删除标签,其他用户的标签仍然存在。
>>> sorted(engine.getTags(users=(u'jodok',))) [u'Austria', u'USA', u'dornbirn', u'lovely', u'personal', u'vacation', u'work'] >>> engine.delete(user=u'jodok') >>> sorted(engine.getTags(users=(u'jodok',))) [] >>> sorted(engine.getTags()) [u'Austria', u'Bizau', u'USA', u'guru', u'lovely', u'zope3']
这也可以用项目实现。
>>> sorted(engine.getTags(items=(3,))) [u'Austria', u'Bizau']
让我们将一个标签从项目添加到另一个项目以展示这种行为。
>>> engine.update(2, u'srichter', [u'Austria']) >>> engine.delete(item=3) >>> sorted(engine.getTags(items=(3,))) []
“奥地利”标签仍然存在。
>>> sorted(engine.getTags()) [u'Austria', u'USA', u'guru', u'lovely', u'zope3']
让我们设置处理器和事件。
>>> from zope.component import eventtesting >>> from zope import event >>> from lovely.tag.engine import removeItemSubscriber >>> from zope.app.intid.interfaces import IntIdRemovedEvent >>> from zope.app.intid import removeIntIdSubscriber >>> zope.component.provideHandler(removeItemSubscriber)
如果我们现在使用图像对象触发intid移除事件,它应该从两个引擎中删除。
>>> len(namedEngine.getItems()) 1 >>> len(engine.getItems()) 2 >>> removeIntIdSubscriber(image, None) >>> len(namedEngine.getItems()) 0 >>> len(engine.getItems()) 1
删除过时项目
您可以从标签引擎中移除过时的项。过时表示该项已无法通过intids实用程序访问。
因为我们之前移除了任何具有intids的对象,所以我们有一个空intid实用程序。
>>> sorted(intIds.refs.keys()) []
但在上面,我们定义了一个具有不存在id的项。因此这是一个过时的项。
>>> sorted(engine.getItems()) [2]
让我们再次添加我们的图像对象。
>>> tagging = tag.interfaces.ITagging(image) >>> tagging.update(u'srichter', [u'newtag'])
这是我们在intid util中的第一个也是唯一的条目。
>>> intIds.refs.keys()[0] in engine.getItems() True
我们的过时条目是2。返回已删除项的intids。
>>> 2 in engine.getItems() True >>> engine.cleanStaleItems() [2]
现在我们只有我们的真实图像项。
>>> 2 in engine.getItems() False >>> len(engine.getItems()) 1 >>> sorted(engine.getItems())[0] == intIds.refs.keys()[0] True
变更
1.1.1 (2009-11-18)
重命名了冲突的“zmi_views”菜单条目。有两个条目名为“管理”。CSVExportView变为“CSV导出”。[trollfot]
1.1.0 (2009-11-18)
修复了标签更新处理中的重要错误:如果对同一用户、项和标签进行了更新,则标签将注册多次。问题来自使用哈希而不是经典cmp方法的集合比较方法。我们必须引入我们称为“大脑”的比较基础,以获得预期的行为。添加了一个测试以强调此行为。[trollfot]
1.0.0 (2009-07-24)
修复了测试以符合最新包。
清理发布说明。
0.3.0b2 (2007-07-18)
如果查询不匹配,lovely.tag将不再返回None,而是一个空的IFTreeSet。(这是由于zope.app.catalog会忽略None,从而导致布尔或运算)
0.3.0b1 (2007-06-13)
使用iobtree进行标签持久化,而不是持久列表和intid实用程序,现在应该对大量标签来说要快得多。(这是一个新的数据库生成)
项目详情
lovely.tag-1.1.1.tar.gz的散列
算法 | 散列摘要 | |
---|---|---|
SHA256 | 47e9a1f1b105e78083cb40be1d76665a516669ae900d29e7503ba792bbbf963a |
|
MD5 | b1e87d4ad0c3bc4b49fe865bb47ce086 |
|
BLAKE2b-256 | 4a0f999f71a74dac72e9266eb411dfae2334c4a9fc4c939ebec37a2399b233ba |