跳转到主要内容

一个小型Zope 3包(也适用于Zope 2.10+和Five),允许您将评分附加到内容。

项目描述

nti.contentratings

此包提供为Zope内容添加评分的基础设施。它支持每个内容对象多个分类评分,并包括用于显示这些评分的视图。有关Plone评分支持,请参阅 plone.contentratings

详细文档

内容评分

这是一个由Zope 3驱动的简单Python包,允许用户(包括未认证用户)对内容进行评分。它提供了一套接口、适配器和视图,允许将评分应用于任何IAnnotatable对象。

依赖项

  • BTrees

  • persistent

  • zope.annotations

  • zope.app.content

  • zope.app.testing

  • zope.component

  • zope.componentvocabulary

  • zope.container

  • zope.interface

  • zope.lifecycleevent

  • zope.location

  • zope.schema

  • zope.tales

所有这些包都包含在Zope 2.12+和Plone 4.0+中。本包与Plone 4.0-4.3进行了测试。

在您的包或产品中使用contentratings

首先将其安装到您的python路径中(不要安装到Products目录中),$INSTANCE_HOME/lib/python可能是开始使用zope的好地方。它可以从Python Cheeseshop(PyPI)作为egg安装。

您需要加载此包的zcml,因此请确保您的应用程序的configure.zcml中包含

<include package="contentratings" />

如果您想允许某些内容被评分,则必须将其标记为可注释的。这是因为评分存储包含在内容对象的注释中。执行此操作的标准方法是向您的产品的configure.zcml中添加以下内容

<content class=".content.MyContentClass">
  <implements
      interface="zope.annotation.interfaces.IAttributeAnnotatable"
      />
</content>

评分类别

此包提供了一种定义< cite>评分类别的基础设施。一个< cite>评分类别是一个实现< cite>IRatingCategory接口的对象,指定一个< cite>标题、< cite>描述(用于UI)、< cite>view_name(在UI中如何渲染和管理评分)、TALES表达式,这些表达式确定何时可以查看或设置评分(< cite>read_expr和< cite>write_expr)、< cite>order(用于UI)以及最终一个< cite>storage(一个工厂,用于创建要存储在注释中的持久化评分API实现)。所有这些属性(除< cite>title外)都是可选的,并提供了合理的默认值。任何对象都可以应用于多个评分类别,每个类别都注册了一个唯一的< cite>name。

默认类别

此包的默认配置提供了两个评分类别。一个用于用户评分,一个用于编辑评分。它们分别注册为标记接口< cite>IUserRatable和< cite>IEditorRatable。用于确定它们何时应用的TALES表达式旨在与Zope 2 CMF应用程序中的对象(主要用于与旧版本的< cite>contentratings保持向后兼容,该版本使用了直接权限检查)一起使用。除非它们想允许所有用户设置和读取评分,否则其他应用程序将需要定义具有自定义条件的类别。

让我们演示如何使用这些类别。我们需要创建一些内容,并用我们的标记接口标记它

>>> from contentratings.tests import SampleContainer
>>> content = SampleContainer()
>>> from contentratings.interfaces import IUserRatable
>>> from zope.interface import alsoProvides
>>> alsoProvides(content, IUserRatable)

现在我们可以使用IUserRating接口将其适配到评分类别

>>> from contentratings.interfaces import IUserRating
>>> adapted = IUserRating(content)
>>> adapted.title
u'User Rating'
>>> float(adapted.averageRating)
0.0
>>> rating = adapted.rate(7.0)
>>> float(adapted.averageRating)
7.0
>>> adapted.numberOfRatings
1
>>> rating = adapted.rate(8.0, 'me')
>>> float(adapted.averageRating)
7.5
>>> adapted.numberOfRatings
2

有关IUserRating API的更多详细信息,请参阅< cite>tests/userstorage.txt。

编辑评分类似,但实现要简单得多

>>> from contentratings.interfaces import IEditorRatable, IEditorialRating
>>> alsoProvides(content, IEditorRatable)
>>> adapted = IEditorialRating(content)
>>> adapted.title
u'Editor Rating'
>>> adapted.rating is None
True
>>> adapted.rating = 6.0
>>> float(adapted.rating)
6.0
>>> adapted.rating = 8.0
>>> float(adapted.rating)
8.0

有关IEditorialRating API的详细信息,请参阅< cite>tests/editorialstorage.txt。

现在让我们删除这些标记,以便我们可以检查自定义类别

>>> from zope.interface import noLongerProvides
>>> noLongerProvides(content, IUserRatable)
>>> noLongerProvides(content, IEditorRatable)
>>> IUserRatable(content) # doctest: +ELLIPSIS
Traceback (most recent call last):
...
TypeError: ('Could not adapt', ...)
>>> IEditorialRating(content) # doctest: +ELLIPSIS
Traceback (most recent call last):
...
TypeError: ('Could not adapt', ...)

自定义评分类别

有两种方法可以创建新的评分类别,一种是声明性地使用ZCML,另一种是直接从Python使用类别工厂。让我们首先看看ZCML方法。要使其生效,我们需要启用zcml指令

>>> from zope.configuration import xmlconfig
>>> import contentratings
>>> context = xmlconfig.file('meta.zcml', contentratings)

加载包配置将自动执行上述操作。

现在我们使用< cite>contentratings:category指令注册我们的评分类别

>>> context = xmlconfig.string("""
... <configure
...    xmlns:contentratings="http://namespaces.plone.org/contentratings">
...  <contentratings:category
...      for="zope.container.sample.SampleContainer"
...      title="My Rating Category"
...      />
... </configure>""", context=context)

在这里,我们使用了所有类别默认值。因此,我们注册了一个使用默认ZODB存储和< cite>IUserRating API的类别,没有限制谁可以获取和设置评分。我们可以很容易地验证这一点,因为类别只是提供由(默认)存储提供的评分接口的适配器

>>> from contentratings.interfaces import IUserRating
>>> content = SampleContainer()
>>> adapted = IUserRating(content)
>>> IUserRating.providedBy(adapted)
True
>>> adapted.context is content
True
>>> adapted.title
u'My Rating Category'

请注意,因为我们没有在配置中提供名称,因此适配器被注册为默认的(未命名的)适配器。类别的名称是适配器注册的名称,并存储在类别的name属性中

>>> adapted.name
''

要提供多个类别,只需使用唯一名称注册它们

>>> context = xmlconfig.string("""
... <configure
...    xmlns:contentratings="http://namespaces.plone.org/contentratings">
...  <contentratings:category
...      for="zope.container.sample.SampleContainer"
...      title="My Other Rating Category"
...      name="other"
...      />
... </configure>""", context=context)
>>> from zope.component import getAdapter
>>> adapted = getAdapter(content, IUserRating, name=u'other')
>>> adapted.title
u'My Other Rating Category'
>>> adapted.name
u'other'

如果我们想以编程方式完成同样的事情,我们可以直接实例化工厂并将其注册为适配器

>>> from contentratings.category import RatingsCategoryFactory
>>> category = RatingsCategoryFactory(title=u'Another Title', name=u'another')
>>> from zope.component import provideAdapter
>>> provideAdapter(category, adapts=(SampleContainer,), provides=IUserRating,
...                name=u'another')
>>> adapted = getAdapter(content, IUserRating, name=u'another')
>>> adapted.title
u'Another Title'
>>> adapted.name
u'another'

这涉及一些冗余,因为存储提供的接口必须显式声明,类别名称必须提供两次。否则它们是等效的。

请注意,类别是适配器,适配器只能以相同名称在不同接口/类下注册。通常,对于给定的名称,将选择注册在最具体接口上的适配器。

评分管理器

当查询与给定评分类别对应的适配器时,返回的对象实际上不是 评分类别 本身,而是一个 评分管理器

>>> adapted # doctest: +ELLIPSIS
<contentratings.category.RatingCategoryAdapter ...>
>>> from contentratings.interfaces import IRatingManager
>>> IRatingManager.providedBy(adapted)
True

评分管理器提供了存储的API,还提供了许多类别属性。它通过检查为类别指定的表达式来保护对存储的直接访问。管理器在类别和上下文上实现为多适配器,但通常不应直接检索。类别适配器负责检索它。管理器负责在内容对象上设置特定类别的存储。

>>> adapted.category # doctest: +ELLIPSIS
<contentratings.category.RatingsCategoryFactory ...>
>>> adapted.context # doctest: +ELLIPSIS
<zope...container.sample.SampleContainer ...>
>>> adapted.storage # doctest: +ELLIPSIS
<contentratings.storage.UserRatingStorage ...>
>>> isinstance(adapted.storage, adapted.category.storage)
True

由于评分管理器负责安全检查和填充TALES表达式上下文,因此应用程序很可能希望用子类替换此组件(本地或特定内容),以提供特定于应用程序的安全性。

视图

评分视图

每个类别都有一个相关的 view_name,这只是一个为评分接口(例如IUserRating)注册的视图的名称,用于在UI中渲染类别。这些在评分管理器中查找,可以访问 IRatingManager API,以及由管理器提供的受保护的评分存储API(例如IUserRating)。

browser/basic.py 中提供了评分视图的可重用基类(BasicUserRatingViewBasicEditorialRatingView)。这些视图使用命名词汇来验证输入,并使用IRatingManager API来确定谁可以和不能对内容进行评分。默认情况下,包配置提供了一些评分视图。

ratings_view (default):  A rating using 1-5 large (25px) stars
small_stars: A rating using 1-5 small (10px) stars
three_small_stars: A rating using 1-3 small (10px) stars

这些都可以通过CSS进行高度自定义。它们都注册为IUserRating。此外,还有一个 rating_view 为IEditorialRating注册。

视图负责查找评分词汇,验证用户输入,以及渲染用户界面。安全性由视图使用的 评分管理器 强制执行,但是视图可以直接从评分管理器访问存储以覆盖表达式检查(例如,显示用户自己的评分,尽管他们看不到别人的)。创建新的视图(例如,非星级评分)非常简单。

提供了一个通用方式有效地确定可重用会话键的实用工具。这可以用来防止匿名用户重复投票。实现自己的匿名会话跟踪机制的应用程序可以在需要时在本地覆盖此实用工具。

聚合视图

还有其他视图,它们找到正在查看的内容对象上所有可用的评分类别,按顺序渲染它们。这些旨在在视图小部件、模块、宏或类似内容中使用。用户评分的聚合视图称为 user-ratings,而编辑评分的聚合视图称为 editorial-ratings

存储

尽管 UserRatingStorage 应该对大多数用例足够,但此包提供了一个简单机制,用于使用自定义对象存储评分。包括两个存储工厂实现,两者都使用ZODB存储评分:一个实现 IUserRating 接口,另一个实现 IEditorialRating 接口。前者旨在用于任何将被多个用户评分(或投票)的内容。后者在内容上存储单个“编辑”评分,主要为了向后兼容。

可以通过使用zcml指令的storage属性或评分类别工厂的storage参数来指定自定义存储工厂(可能从包含的实现之一派生而来)。

不仅存储可以替换,它们还可以实现完全定制的API来管理评分。尽管这种需求可能有限,您可以通过创建一个管理评分的接口并让该接口提供IRatingType来创建自定义存储API。有关更多信息,请参阅tests/中的存储文档。

为什么需要新的评分包

已经有ATRatingslovely.ratingiqpp.ratingiqpp.plone.rating等包,为什么还需要另一个包呢?

首先,contentratings在所有这些包中都是第一个出现的,除了ATRatings,后者仅在Plone的Archetypes内容下有用。contentratings最初是一个非常简单的包,旨在让开发人员更容易地将评分添加到他们的产品和应用中。然而,似乎有很多需求,需要一个终端用户产品来简化将评分添加到现有内容对象中。

不幸的是,这些包中没有哪一个直接支持单个内容对象上的多个评分,这似乎是一个常见需求。它(以及lovely.rating)以一种可能对希望允许用户自定义评分的产品不理想的方式将评分评分系统与视图解耦。要支持这些用例,需要对这些包进行彻底的重写。因此,我重写了这些评分包中最简单(也是最熟悉)的一个,以支持这些用例,并为Plone终端用户创建了一个新的包来整合这些新功能(请参阅plone.contentratings)。

待办事项

  • 提供视图自定义示例

  • 使视图与Zope 3身份验证一起工作

  • 将plone.contentratings中的KSS视图移植到contentratings中(它目前依赖于一些plone KSS命令)

鸣谢

作者

贡献者

  • Maurizio Delmonte

(如果您做出了重大贡献,请自由地在上面的名称中添加您的名字)

感谢以下人员

  • Geoff DavisATRatings的作者,从其中借鉴了图标和想法。

  • Philipp von WeitershausenWeb Component Development with Zope 3的作者,它提供了一个基于注释的评分产品的良好示例,这是本实现的开端。

  • Kai Diefenbachiqpp.plone.rating的作者,从中借鉴了其他图标和UI想法。

  • 一些图标来自Mark JamesSilk icon set 1.3

  • 星级评分基于CSS Star Rating Redux,通过iqpp.plone.rating

更改日志

1.2.0 (2021-04-13)

  • 修复了评分操作中的XSS漏洞 [keul, cekk]

  • 添加了对Python 3的支持。

  • 添加了对PyPy的支持。

  • 移除了对Python 2.6的支持。

  • 添加了对zope.component 5的支持。

1.1 (2013-09-20)

  • 更新以支持Zope 2.13和Plone 4.0至4.3,并清理依赖项。

1.0-final(2011-08-21)

  • 为chameleon兼容性修复模板标记。

  • 添加了巴斯克语和加泰罗尼亚语的翻译。

1.0-rc3(2011-05-12)

  • 优化平均/计数计算,以处理大量评分。提高最近评分查找的性能。

  • 针对Plone 4.1的修复

1.0-rc2(2010-11-28)

  • 仅在只读评分视图中不使用CSS id,以便带有评分的列表仍然具有有效的HTML。

1.0-rc1(2010-08-31)

  • 添加对只读评分视图的支持。

  • 移除_v属性缓存。

  • Plone 4 / Zope 2.12兼容性(仍在Plone 3.3.4 / Zope 2.10.11上工作)
    • permissions.py:不要依赖于Products.__ac_permissions__

    • 从AccessControl.Permission导入ApplicationDefaultPermissions

    • 修复测试
      • traverser.py, README.txt: SampleContainer 类可能来自 zope.* 和 zope.app.*

      • utils.py: 日期可能后跟分号,也可能不跟。

    • browser/basic.py: 向 BasicEditorialRatingView 添加 publishTraverse 方法,以防止错误的遍历。

    • events.py 和 interfaces.py: 从 IObjectEvent (而不是从 IObjectModifiedEvent) 继承 IObjectRatedEvent 以防止权限错误。

  • 添加此文件

0.2 (2009-05-11)

项目详情


下载文件

下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。

源分发

nti.contentratings-1.2.0.tar.gz (72.7 kB 查看哈希值)

上传时间

构建分发

nti.contentratings-1.2.0-py2.py3-none-any.whl (94.4 kB 查看哈希值)

上传时间 Python 2 Python 3

由以下支持