跳转到主要内容

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.getTags(items=(1,)))
[u'USA', u'personal']

注意:查询方法返回集合。

>>> type(engine.getTags())
<type 'set'>

该方法始终返回标准化后的标签字符串。您也可以指定多个项

>>> sorted(engine.getTags(items=(1, 2)))
[u'USA', u'austria', u'lovely', u'personal', u'work']

您还可以请求用户的标签

>>> sorted(engine.getTags(users=(u'srichter',)))
[u'USA', u'austria', u'lovely', u'personal']

同样,您也可以指定多个用户

>>> sorted(engine.getTags(users=(u'srichter', u'jodok')))
[u'Austria', u'USA', u'austria', u'lovely', u'personal', u'work']

最后,您也可以指定两者的组合

>>> sorted(engine.getTags(items=(1,), users=(u'srichter',)))
[u'USA', u'personal']
>>> sorted(engine.getTags(items=(1, 2), users=(u'srichter',)))
[u'USA', u'austria', u'lovely', u'personal']
>>> sorted(engine.getTags(items=(3,), users=(u'srichter',)))
[]

您还可以不指定项或用户来查询所有标签

>>> sorted(engine.getTags())
[u'Austria', u'USA', u'austria', u'lovely', u'personal', 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)]

标签频率

如果我们有一个标签列表,我们可以请求标签的频率。

>>> sorted(engine.getFrequency([u'Austria', u'USA']))
[(u'Austria', 2), (u'USA', 3)]

如果我们请求的标签不在引擎中,我们得到的频率为0。

>>> sorted(engine.getFrequency([u'Austria', u'jukart', u'USA']))
[(u'Austria', 2), (u'USA', 3), (u'jukart', 0)]

删除标签对象

当对象从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

重命名标签

您还可以在引擎中全局重命名标签。

>>> tagging.update(u'srichter', [u'tagtorename', u'usa'])
>>> tagging.update(u'jukart', [
...     u'tagtorename', u'someothertag', u'renamedtag'])
>>> engine.update(123, 'jukart', [u'tagtorename'])
>>> sorted(engine.getTags())
[u'renamedtag', u'someothertag', u'tagtorename', u'usa']
>>> sorted(engine.getTags(users=[u'jukart']))
[u'renamedtag', u'someothertag', u'tagtorename']
>>> len(sorted(engine.getItems(tags=[u'tagtorename'])))
2
>>> len(sorted(engine.getItems(tags=[u'renamedtag'])))
1
>>> sorted(engine.getTags(users=[u'srichter']))
[u'tagtorename', u'usa']

重命名方法返回重命名标签对象的数量。

>>> engine.rename(u'tagtorename', u'renamedtag')
3
>>> sorted(engine.getTags())
[u'renamedtag', u'someothertag', u'usa']

如果新名称已存在,则标签将被连接。

>>> sorted(engine.getTags(users=[u'jukart']))
[u'renamedtag', u'someothertag']
>>> sorted(engine.getTags(users=[u'srichter']))
[u'renamedtag', u'usa']
>>> len(sorted(engine.getItems(tags=[u'tagtorename'])))
0
>>> len(sorted(engine.getItems(tags=[u'renamedtag'])))
2

规范化标签

您还可以使用可调用的对象规范化标签,该对象为任何给定的名称返回一个新名称。小写。

>>> engine.update(123, 'jukart', [u'RenamedTag', u'USA'])
>>> sorted(engine.getTags())
[u'RenamedTag', u'USA', u'renamedtag', u'someothertag', u'usa']

让我们使用字符串模块中的lower函数将所有标签规范化为小写。

>>> import string

规范化方法返回受影响的标签对象数量。

>>> engine.normalize(string.lower)
2
>>> sorted(engine.getTags())
[u'renamedtag', u'someothertag', u'usa']

规范化方法还接受Python点名称,它将被解析为全局对象。

>>> engine.normalize('string.upper')
7
>>> sorted(engine.getTags())
[u'RENAMEDTAG', u'SOMEOTHERTAG', u'USA']

变更

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 (216.6 KB 查看散列)

上传时间

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面