跳转到主要内容

应用程序设置注册表(如debconf/ about:config)

项目描述

简介

此软件包为 Zope 应用程序提供了类似于 debconf(或 about:config-like)的设置注册表。一个注册表,具有类似字典的 API,用于获取和设置存储在 records 中的值。每个记录包含实际值以及一个更详细地描述记录的 field。至少,该字段包含有关允许的值类型的信息,以及描述记录目的的简短标题。

使用注册表

您可以通过实例化 Registry 类来创建一个新的注册表。该类及其数据结构是持久的,因此您可以将其存储在 ZODB 中。您可能还想将注册表对象作为本地实用工具提供,以便于访问,尽管我们在这里不会这样做。

>>> from plone.registry import Registry
>>> registry = Registry()

注册表最初是空的。要访问注册表的记录,您可以使用 records 属性。这公开了一个字典 API,其中键是字符串,值是提供 IRecords 的对象。

>>> len(registry.records)
0

简单记录

现在让我们创建一个记录。记录必须有一个名称。这应该是一个点名称,只包含 ASCII 字符。按照惯例,它应该是全部小写并以定义记录的包的名称开头。

还可以根据单个模式接口创建多个记录 - 见下文。现在,我们将专注于简单记录。

在我们可以创建记录之前,我们必须创建描述它的字段。字段基于备受尊敬的 zope.schema 包。 plone.registry 只支持某些字段,并禁止使用其中一些字段的某些属性。作为一个经验法则,只要字段存储 Python 基本类型,它就是受支持的;同样适用于字段的属性。

因此

  • ObjectInterfaceField 等字段是不受支持的。

  • 不支持自定义 constraint 方法。

  • 将始终将 order 属性设置为 -1

  • 对于选择字段,仅支持 命名词汇表:您无法引用特定的 源绑定器

  • Dict、List、Tuple、Set 和 Frozenset 的 key_typevalue_type 属性只能包含持久字段。

有关更多详细信息,请参阅“持久字段”部分。

创建记录

支持的字段类型位于 plone.registry.field 模块中。这些名称与 zope.schema 中等效的字段相同,并且具有相同的构造函数。在直接创建记录时,您必须使用这些字段之一

>>> from plone.registry import field
>>> age_field = field.Int(title=u"Age", min=0, default=18)

>>> from plone.registry import Record
>>> age_record = Record(age_field)

请注意,在这种情况下,我们没有提供值。因此,值将是字段的默认值

>>> age_record.value
18

我们可以在 Record 构造函数或通过 value 属性设置不同的值

>>> age_record.value = 2
>>> age_record.value
2

请注意,值将针对字段进行验证

>>> age_record.value = -1
Traceback (most recent call last):
...
zope.schema._bootstrapinterfaces.TooSmall: (-1, 0)

>>> age_record.value
2

现在我们可以将字段添加到注册表中。这是通过 record 字典完成的

>>> 'plone.registry.tests.age' in registry
False
>>> registry.records['plone.registry.tests.age'] = age_record

此时,记录将获得 __name____parent__ 属性

>>> age_record.__name__
'plone.registry.tests.age'

>>> age_record.__parent__ is registry
True

带有初始值的记录创建

我们可以通过以下方式一次性简洁地创建记录:

  1. 创建字段

  2. 创建记录并设置其值

  3. 将其分配给注册表

如下所示

>>> registry.records['plone.registry.tests.cms'] = \
...     Record(field.TextLine(title=u"CMS of choice"), u"Plone")

现在可以获取记录。请注意,它有一个漂亮的 __repr__ 帮助调试。

>>> registry.records['plone.registry.tests.cms']
<Record plone.registry.tests.cms>

访问和操作记录值

一旦创建并添加到注册表,您可以通过在注册表本身上进行类似于字典的操作来访问其值

>>> 'plone.registry.tests.cms' in registry
True

>>> registry['plone.registry.tests.cms']  # doctest: +IGNORE_U
u'Plone'

>>> registry['plone.registry.tests.cms'] = u"Plone 3.x"

再次提醒,值将进行验证

>>> registry['plone.registry.tests.cms'] = b'Joomla'
Traceback (most recent call last):
...
zope.schema._bootstrapinterfaces.WrongType: (b'Joomla', <class 'str'>, 'value')

还有一个 get() 方法

>>> registry.get('plone.registry.tests.cms')  # doctest: +IGNORE_U
u'Plone 3.x'
>>> registry.get('non-existent-key') is None
True

删除记录

可以从 records 属性中删除记录

>>> del registry.records['plone.registry.tests.cms']
>>> 'plone.registry.tests.cms' in registry.records
False
>>> 'plone.registry.tests.cms' in registry
False

从接口创建记录

作为应用程序开发人员,通常希望使用 zope.schema fields 将设置定义为传统的接口。 plone.registry 包括从单个接口创建记录集的支持。

为了测试这一点,我们创建了一个接口,IMailSettings。它有两个字段:sendersmtp_host

>>> from plone.registry.tests import IMailSettings

请注意,这包含标准字段

>>> IMailSettings['sender']
<zope.schema._bootstrapfields.TextLine object at ...>

>>> IMailSettings['smtp_host']
<zope.schema._field.URI object at ...>

我们可以像这样从该接口创建记录

>>> registry.registerInterface(IMailSettings)

现在已为接口中的每个字段创建了一个记录。它们的名称是这些字段的完整点分名称

>>> sender_record = registry.records['plone.registry.tests.IMailSettings.sender']
>>> smtp_host_record = registry.records['plone.registry.tests.IMailSettings.smtp_host']

记录中使用的字段将是原始接口中字段的等效持久版本

>>> sender_record.field
<plone.registry.field.TextLine object at ...>

>>> smtp_host_record.field
<plone.registry.field.URI object at ...>

这一功能通过将字段适配到 IPersistentField 接口在内部实现。有一个默认适配器工厂适用于在 plone.registry.field 中定义的所有字段。当然,如果您有自定义字段类型,可以定义自己的适配器。但请记住持久字段的黄金法则

* The field must store only primitives or other persistent fields
* It must not reference a function, class, interface or other method that could break if a package is uninstalled.

如果我们有一个没有 IPersistentField 适配器的字段,我们将得到一个错误

>>> from plone.registry.tests import IMailPreferences
>>> IMailPreferences['settings']
<zope.schema._bootstrapfields.Object object at ...>

>>> registry.registerInterface(IMailPreferences)
Traceback (most recent call last):
...
TypeError: There is no persistent field equivalent for the field `settings` of type `Object`.

哎呀!然而,我们可以告诉 registerInterface() 忽略一个或多个字段

>>> registry.registerInterface(IMailPreferences, omit=('settings',))

一旦接口的记录被注册,我们可以像通常一样获取和设置它们的值

>>> registry['plone.registry.tests.IMailSettings.sender']  # doctest: +IGNORE_U
u'root@localhost'

>>> registry['plone.registry.tests.IMailSettings.sender'] = u"webmaster@localhost"
>>> registry['plone.registry.tests.IMailSettings.sender']  # doctest: +IGNORE_U
u'webmaster@localhost'

如果我们随后重新注册相同的接口,如果可能,将保留值

>>> registry.registerInterface(IMailSettings)
>>> registry['plone.registry.tests.IMailSettings.sender']  # doctest: +IGNORE_U
u'webmaster@localhost'

但是,如果值不再有效,我们将回滚到默认值。为了测试这一点,让我们暂时修改字段

>>> old_field = IMailSettings['sender']
>>> IMailSettings._InterfaceClass__attrs['sender'] = field.Int(title=u"Definitely not a string", default=2)
>>> if hasattr(IMailSettings, '_v_attrs'):
...     del IMailSettings._v_attrs['sender']
>>> registry.registerInterface(IMailSettings)
>>> registry['plone.registry.tests.IMailSettings.sender']
2

但我们将其恢复到原来的样子

>>> IMailSettings._InterfaceClass__attrs['sender'] = old_field
>>> if hasattr(IMailSettings, '_v_attrs'):
...     del IMailSettings._v_attrs['sender']
>>> registry.registerInterface(IMailSettings)
>>> registry['plone.registry.tests.IMailSettings.sender']  # doctest: +IGNORE_U
u'root@localhost'

有时,您可能希望将接口用作一组字段的模板,而不是手动定义所有字段。这在您希望允许第三方包提供信息时特别有用。为了实现这一点,我们可以在调用 registerInterface 时提供一个前缀。这将优先于通常使用的 __identifier__

>>> registry.registerInterface(IMailSettings, prefix="plone.registry.tests.alternativesettings")

这些值现在以与原始设置相同的方式提供

>>> sender_record = registry.records['plone.registry.tests.alternativesettings.sender']
>>> smtp_host_record = registry.records['plone.registry.tests.alternativesettings.smtp_host']
>>> registry['plone.registry.tests.alternativesettings.sender'] = u'alt@example.org'

访问原始接口

现在我们有了这些记录,我们可以查找原始接口。这不会打破黄金法则:在内部,我们只存储接口的名称,并在运行时解析。

了解接口的记录用 IInterfaceAwareRecord 标记,并有两个额外的属性: interfacefieldName

>>> from plone.registry.interfaces import IInterfaceAwareRecord
>>> IInterfaceAwareRecord.providedBy(age_record)
False
>>> IInterfaceAwareRecord.providedBy(sender_record)
True

>>> sender_record.interfaceName
'plone.registry.tests.IMailSettings'

>>> sender_record.interface is IMailSettings
True

使用记录代理

一旦创建了接口的记录,就可以获取一个提供给定接口的代理对象,但将其值读取和写入注册表。例如,使用 zope.formlibz3c.form 创建表单时,这很有用,配置了基于接口的控件。或者简单地作为一个更方便的API,当处理多个相关设置时。

>>> proxy = registry.forInterface(IMailSettings)
>>> proxy
<RecordsProxy for plone.registry.tests.IMailSettings>

如果您在代码中使用可能在正常HTML渲染路径上遇到(例如在视图组件中)的注册值,您需要知道记录可能不存在或不有效。 forInterface() 在这种情况下将引发 KeyError

try:
    proxy = registry.forInterface(IMailSettings)
except KeyError:
    # Gracefully handled cases
    # when GenericSetup installer has not been run or rerun
    # e.g. by returning or using some default values
    pass

代理本身不是一个持久对象

>>> from persistent.interfaces import IPersistent
>>> IPersistent.providedBy(proxy)
False

然而,它确实提供了必要的接口

>>> IMailSettings.providedBy(proxy)
True

您可以通过检查 IRecordsProxy 标记接口来区分代理和“正常”对象

>>> from plone.registry.interfaces import IRecordsProxy
>>> IRecordsProxy.providedBy(proxy)
True

当我们设置值时,它将存储在注册表中

>>> proxy.smtp_host = 'http://mail.server.com'
>>> registry['plone.registry.tests.IMailSettings.smtp_host']
'http://mail.server.com'

>>> registry['plone.registry.tests.IMailSettings.smtp_host'] = 'smtp://mail.server.com'
>>> proxy.smtp_host
'smtp://mail.server.com'

不在接口中的值将引发 AttributeError

>>> proxy.age
Traceback (most recent call last):
...
AttributeError: age

请注意,默认情况下,forInterface() 方法将检查必要的记录是否已注册。例如,我们不能使用任何旧的接口

>>> registry.forInterface(IInterfaceAwareRecord)
Traceback (most recent call last):
...
KeyError: 'Interface `plone.registry.interfaces.IInterfaceAwareRecord` defines a field `...`, for which there is no record.'

默认情况下,我们也不能使用仅存在一些记录的接口

>>> registry.forInterface(IMailPreferences)
Traceback (most recent call last):
...
KeyError: 'Interface `plone.registry.tests.IMailPreferences` defines a field `settings`, for which there is no record.'

然而,可以禁用此检查。这将更有效一点

>>> registry.forInterface(IMailPreferences, check=False)
<RecordsProxy for plone.registry.tests.IMailPreferences>

更好的方法是明确声明一些字段被省略

>>> pref_proxy = registry.forInterface(IMailPreferences, omit=('settings',))

在这种情况下,省略的字段将默认为它们的“缺失”值

>>> pref_proxy.settings ==  IMailPreferences['settings'].missing_value
True

然而,尝试设置值将导致 AttributeError

>>> pref_proxy.settings = None
Traceback (most recent call last):
...
AttributeError: settings

要访问字段的另一个实例,提供前缀

>>> alt_proxy = registry.forInterface(IMailSettings,
...     prefix="plone.registry.tests.alternativesettings")
>>> alt_proxy.sender  # doctest: +IGNORE_U
u'alt@example.org'

记录代理的集合

可以使用 collectionOfInterface 访问记录集的集合

>>> collection = registry.collectionOfInterface(IMailSettings)

您可以创建一个新的记录集

>>> proxy = collection.setdefault('example')
>>> proxy.sender = u'collection@example.org'
>>> proxy.smtp_host = 'smtp://mail.example.org'

记录集基于前缀存储

>>> prefix = IMailSettings.__identifier__
>>> registry.records.values(prefix+'/', prefix+'0')
[<Record plone.registry.tests.IMailSettings/example.sender>,
 <Record plone.registry.tests.IMailSettings/example.smtp_host>]
>>> registry['plone.registry.tests.IMailSettings/example.sender']  # doctest: +IGNORE_U
u'collection@example.org'

可以从现有对象设置记录

>>> class MailSettings:
...     sender = u'someone@example.com'
...     smtp_host = 'smtp://mail.example.com'
>>> collection['example_com'] = MailSettings()
>>> registry.records.values(prefix+'/', prefix+'0')
[<Record plone.registry.tests.IMailSettings/example.sender>,
 <Record plone.registry.tests.IMailSettings/example.smtp_host>,
 <Record plone.registry.tests.IMailSettings/example_com.sender>,
 <Record plone.registry.tests.IMailSettings/example_com.smtp_host>]

可以遍历集合

>>> for name in collection: print(name)
example
example_com

并且可以删除

>>> del collection['example_com']
>>> registry.records.values(prefix+'/', prefix+'0')
[<Record plone.registry.tests.IMailSettings/example.sender>,
 <Record plone.registry.tests.IMailSettings/example.smtp_host>]

使用字段引用

一个记录可以引用另一个记录的字段。这可以用来提供一个简单的“覆盖”机制,例如,一个记录定义了字段和默认值,而另一个提供对同一字段的有效覆盖。

让我们首先创建基本记录并设置其值

>>> timeout_field = field.Int(title=u"Timeout", min=0)
>>> registry.records['plone.registry.tests.timeout'] = Record(timeout_field, 10)

>>> timeout_record = registry.records['plone.registry.tests.timeout']
>>> timeout_record.value
10

接下来,我们为这个记录创建一个字段引用

>>> from plone.registry import FieldRef
>>> timeout_override_field = FieldRef(timeout_record.__name__, timeout_record.field)

我们可以使用它来创建一个新的记录

>>> registry.records['plone.registry.tests.timeout.override'] = Record(timeout_override_field, 20)
>>> timeout_override_record = registry.records['plone.registry.tests.timeout.override']

这两个值是分开的

>>> timeout_record.value
10
>>> timeout_override_record.value
20

>>> registry['plone.registry.tests.timeout']
10
>>> registry['plone.registry.tests.timeout.override']
20

验证使用底层字段

>>> registry['plone.registry.tests.timeout.override'] = -1
Traceback (most recent call last):
...
zope.schema._bootstrapinterfaces.TooSmall: (-1, 0)

引用字段公开标准字段属性,例如

>>> timeout_override_record.field.title
'Timeout'
>>> timeout_override_record.field.min
0

要查找底层记录名称,我们可以使用 recordName 属性

>>> timeout_override_record.field.recordName
'plone.registry.tests.timeout'

注册表事件

注册表会触发某些事件。这些是

plone.registry.interfaces.IRecordAddedEvent

当记录被添加到注册表时。

plone.registry.interfaces.IRecordRemovedEvent

当一条记录从注册表中删除时。

plone.registry.interfaces.IRecordModifiedEvent,

当一条记录的值被修改时。

为了测试这些事件,我们将创建、修改和删除一些记录

>>> from zope.component.eventtesting import clearEvents
>>> clearEvents()
>>> from plone.registry import Registry, Record, field
>>> registry = Registry()

向注册表中添加新记录应触发 IRecordAddedEvents

>>> registry.records['plone.registry.tests.age'] = \
...     Record(field.Int(title=u"Age", min=0, default=18))

>>> registry.records['plone.registry.tests.cms'] = \
...     Record(field.TextLine(title=u"Preferred CMS"), value=u"Plone")

从接口创建记录时,每个接口字段都会触发一个事件

>>> from plone.registry.tests import IMailSettings
>>> registry.registerInterface(IMailSettings)

删除记录应触发 IRecordRemovedEvent

>>> del registry.records['plone.registry.tests.cms']

更改记录应触发 IRecordModifiedEvent

>>> registry['plone.registry.tests.age'] = 25
>>> registry.records['plone.registry.tests.age'].value = 24

让我们看看刚刚触发的事件

>>> from plone.registry.interfaces import IRecordEvent
>>> from zope.component.eventtesting import getEvents
>>> getEvents(IRecordEvent)
[<RecordAddedEvent for plone.registry.tests.age>,
 <RecordAddedEvent for plone.registry.tests.cms>,
 <RecordAddedEvent for plone.registry.tests.IMailSettings.sender>,
 <RecordAddedEvent for plone.registry.tests.IMailSettings.smtp_host>,
 <RecordRemovedEvent for plone.registry.tests.cms>,
 <RecordModifiedEvent for plone.registry.tests.age>,
 <RecordModifiedEvent for plone.registry.tests.age>]

对于修改事件,我们还可以检查更改前后的值

>>> from plone.registry.interfaces import IRecordModifiedEvent
>>> [(repr(e), e.oldValue, e.newValue,) for e in getEvents(IRecordModifiedEvent)]
[('<RecordModifiedEvent for plone.registry.tests.age>', 18, 25),
 ('<RecordModifiedEvent for plone.registry.tests.age>', 25, 24)]

IObjectEvent 风格的重新调度器

有一个特殊的事件处理器。它根据记录指定的架构接口重新分配注册表事件

让我们重新设置事件测试框架并注册重新分配事件订阅者。通常,这会通过包含此包的 ZCML 自动完成。

>>> clearEvents()
>>> from zope.component import provideHandler
>>> from plone.registry.events import redispatchInterfaceAwareRecordEvents
>>> provideHandler(redispatchInterfaceAwareRecordEvents)

然后我们将注册一个架构接口

>>> from plone.registry.tests import IMailSettings
>>> registry.registerInterface(IMailSettings)

现在,我们可以注册一个事件处理器来打印 IMailSettings 记录上发生的任何记录事件。当然,还可以注册针对例如 IRecordModifiedEventIRecordRemovedEvent 的更专业的事件处理器。请注意,无法重新分配 IRecordAddedEvents,因此它们永远不会被捕获。

>>> from zope.component import adapter
>>> @adapter(IMailSettings, IRecordEvent)
... def print_mail_settings_events(proxy, event):
...     print("Got %s for %s" % (event, proxy))
>>> provideHandler(print_mail_settings_events)

现在让我们修改该接口中的一个记录。事件处理器应立即做出反应

>>> registry['plone.registry.tests.IMailSettings.sender'] = u"Some sender"
Got <RecordModifiedEvent for plone.registry.tests.IMailSettings.sender> for <RecordsProxy for plone.registry.tests.IMailSettings>

为了比较,我们还可以修改一个非接口感知的记录。这里,没有打印出任何内容

>>> registry['plone.registry.tests.age'] = 3

我们还可以尝试记录删除事件

>>> del registry.records['plone.registry.tests.IMailSettings.sender']
Got <RecordRemovedEvent for plone.registry.tests.IMailSettings.sender> for <RecordsProxy for plone.registry.tests.IMailSettings>

已分发的基事件有

>>> getEvents(IRecordEvent)
[<RecordAddedEvent for plone.registry.tests.IMailSettings.sender>,
 <RecordAddedEvent for plone.registry.tests.IMailSettings.smtp_host>,
 <RecordModifiedEvent for plone.registry.tests.IMailSettings.sender>,
 <RecordModifiedEvent for plone.registry.tests.age>,
 <RecordRemovedEvent for plone.registry.tests.IMailSettings.sender>]

持久字段

plone.registry.field 中找到的持久字段是 zope.schema 中找到的字段兄弟,其中混合了持久性。为了避免由于对可能消失的符号的持久引用而破坏注册表,我们故意限制了支持的字段数量。我们还禁止了一些属性,并对其他属性增加了额外的检查。

标准字段

我们将依次展示每个支持的字段。对于所有字段,请注意

  • 无论 constraint 属性的设置如何,order 属性都将返回 -1

  • 如果适用,key_typevalue_type 属性必须设置为持久字段。

  • 对于 Choice 字段,仅支持命名词汇表和基于简单值的词汇表:源和 IVocabulary 对象不受支持。

需要导入的内容

>>> from plone.registry import field
>>> from zope import schema
>>> from persistent import Persistent

字节

bytes 字段描述一个字节字符串

>>> f = field.Bytes(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.Bytes)
True

>>> f.order
-1

>>> field.Bytes(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint('ABC')
True

字节行

bytes 字段描述一个不允许换行的字节字符串

>>> f = field.BytesLine(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.BytesLine)
True

>>> f.order
-1

>>> field.BytesLine(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(b'AB\nC')
False

ASCII

ASCII 字段描述一个仅包含 ASCII 字符的字符串

>>> f = field.ASCII(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.ASCII)
True

>>> f.order
-1

>>> field.ASCII(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint('ab\nc')
True

ASCII 行

ASCII 行字段描述一个仅包含 ASCII 字符并禁止换行的字符串

>>> f = field.ASCIILine(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.ASCIILine)
True

>>> f.order
-1

>>> field.ASCIILine(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint('ab\nc')
False

文本

text 字段描述一个 Unicode 字符串

>>> f = field.Text(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.Text)
True

>>> f.order
-1

>>> field.Text(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(u'ab\nc')
True

文本行

text 行字段描述一个不允许换行的 Unicode 字符串

>>> f = field.TextLine(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.TextLine)
True

>>> f.order
-1

>>> field.TextLine(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(u'ab\nc')
False

布尔值

bool 字段描述一个布尔值

>>> f = field.Bool(title=u"Test")
>>> isinstance(f, schema.Bool)
True

>>> f.order
-1

>>> field.Bool(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(False)
True

整型

int 字段描述一个整数或长整型

>>> f = field.Int(title=u"Test", min=-123, max=1234)
>>> isinstance(f, schema.Int)
True

>>> f.order
-1

>>> field.Int(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(123)
True

浮点型

float 字段描述一个浮点数

>>> f = field.Float(title=u"Test", min=-123.0, max=1234.0)
>>> isinstance(f, schema.Float)
True

>>> f.order
-1

>>> field.Float(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(123)
True

十进制

decimal 字段描述一个十进制数

>>> import decimal
>>> f = field.Decimal(title=u"Test", min=decimal.Decimal('-123.0'), max=decimal.Decimal('1234.0'))
>>> isinstance(f, schema.Decimal)
True

>>> f.order
-1

>>> field.Decimal(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(123)
True

密码

password 字段描述用于密码的 Unicode 字符串

>>> f = field.Password(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.Password)
True

>>> f.order
-1

>>> field.Password(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(u'ab\nc')
False

源文本

source text 字段描述包含源代码的 Unicode 字符串

>>> f = field.SourceText(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.SourceText)
True

>>> f.order
-1

>>> field.SourceText(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(u'ab\nc')
True

URI

URI 字段描述 URI 字符串

>>> f = field.URI(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.URI)
True

>>> f.order
-1

>>> field.URI(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(u'abc')
True

标识符

id 字段描述 URI 字符串或点分名称

>>> f = field.Id(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.Id)
True

>>> f.order
-1

>>> field.Id(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(u'abc')
True

点名称

点分名称字段描述 Python 点分名称

>>> f = field.DottedName(title=u"Test", min_length=0, max_length=10)
>>> isinstance(f, schema.DottedName)
True

>>> f.order
-1

>>> field.DottedName(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(u'abc')
True

日期时间

日期/时间字段描述 Python datetime 对象

>>> f = field.Datetime(title=u"Test")
>>> isinstance(f, schema.Datetime)
True

>>> f.order
-1

>>> field.Datetime(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> import datetime
>>> f.constraint(datetime.datetime.now())
True

日期

日期字段描述 Python 日期对象

>>> f = field.Date(title=u"Test")
>>> isinstance(f, schema.Date)
True

>>> f.order
-1

>>> field.Date(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> import datetime
>>> f.constraint(datetime.date.today())
True

时间差

时间差字段描述了一个Python timedelta对象

>>> f = field.Timedelta(title=u"Test")
>>> isinstance(f, schema.Timedelta)
True

>>> f.order
-1

>>> field.Timedelta(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> import datetime
>>> f.constraint(datetime.timedelta(1))
True

元组

元组字段描述了一个元组

>>> f = field.Tuple(title=u"Test", min_length=0, max_length=10,
...     value_type=field.TextLine(title=u"Value"))
>>> isinstance(f, schema.Tuple)
True

>>> f.order
-1

>>> field.Tuple(title=u"Test", min_length=0, max_length=10,
...     value_type=schema.TextLine(title=u"Value"))
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> f.value_type = schema.TextLine(title=u"Value")
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> field.Tuple(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint((1,2))
True

列表

列表字段描述了一个元组

>>> f = field.List(title=u"Test", min_length=0, max_length=10,
...     value_type=field.TextLine(title=u"Value"))
>>> isinstance(f, schema.List)
True

>>> f.order
-1

>>> field.List(title=u"Test", min_length=0, max_length=10,
...     value_type=schema.TextLine(title=u"Value"))
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> f.value_type = schema.TextLine(title=u"Value")
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> field.List(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint([1,2])
True

集合

集合字段描述了一个集合

>>> f = field.Set(title=u"Test", min_length=0, max_length=10,
...     value_type=field.TextLine(title=u"Value"))
>>> isinstance(f, schema.Set)
True

>>> f.order
-1

>>> field.Set(title=u"Test", min_length=0, max_length=10,
...     value_type=schema.TextLine(title=u"Value"))
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> f.value_type = schema.TextLine(title=u"Value")
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> field.Set(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(set([1,2]))
True

冻结集合

集合字段描述了一个frozenset

>>> f = field.FrozenSet(title=u"Test", min_length=0, max_length=10,
...     value_type=field.TextLine(title=u"Value"))
>>> isinstance(f, schema.FrozenSet)
True

>>> f.order
-1

>>> field.FrozenSet(title=u"Test", min_length=0, max_length=10,
...     value_type=schema.TextLine(title=u"Value"))
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> f.value_type = schema.TextLine(title=u"Value")
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> field.FrozenSet(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(frozenset([1,2]))
True

字典

集合字段描述了一个字典

>>> f = field.Dict(title=u"Test", min_length=0, max_length=10,
...     key_type=field.ASCII(title=u"Key"),
...     value_type=field.TextLine(title=u"Value"))
>>> isinstance(f, schema.Dict)
True

>>> f.order
-1

>>> field.Dict(title=u"Test", min_length=0, max_length=10,
...     key_type=schema.ASCII(title=u"Key"),
...     value_type=field.TextLine(title=u"Value"))
Traceback (most recent call last):
...
ValueError: The property `key_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> f.key_type = schema.ASCII(title=u"Key")
Traceback (most recent call last):
...
ValueError: The property `key_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> field.Dict(title=u"Test", min_length=0, max_length=10,
...     key_type=field.ASCII(title=u"Key"),
...     value_type=schema.TextLine(title=u"Value"))
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> f.value_type = schema.TextLine(title=u"Value")
Traceback (most recent call last):
...
ValueError: The property `value_type` may only contain objects providing `plone.registry.interfaces.IPersistentField`.

>>> field.Dict(title=u"Test", constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint(dict())
True

选择

选择字段代表从词汇表中选择。对于持久字段,词汇表不能是或任何类型的对象:它必须是一个原语列表,或者是一个命名的词汇表

>>> f = field.Choice(title=u"Test", values=[1,2,3])
>>> isinstance(f, schema.Choice)
True

>>> f.order
-1

给定一个值列表,vocabulary属性会根据值动态构建一个词汇表,并且vocabularyNameNone

>>> f.vocabulary
<zope.schema.vocabulary.SimpleVocabulary object at ...>

>>> f.vocabularyName is None
True

如果我们使用除了原语以外的任何东西,将会得到一个错误

>>> f = field.Choice(title=u"Test", values=[object(), object()])
Traceback (most recent call last):
...
ValueError: Vocabulary values may only contain primitive values.

如果给出了词汇名称,它将被存储在vocabularyName中,并且vocabulary属性返回None

>>> f = field.Choice(title=u"Test", vocabulary='my.vocab')
>>> f.vocabulary is None
True

>>> f.vocabularyName
'my.vocab'

现在允许其他组合,例如指定没有词汇

>>> field.Choice(title=u"Test")
Traceback (most recent call last):
...
AssertionError: You must specify either values or vocabulary.

或者指定两种类型

>>> field.Choice(title=u"Test", values=[1,2,3], vocabulary='my.vocab')
Traceback (most recent call last):
...
AssertionError: You cannot specify both values and vocabulary.

或者指定对象源

>>> from zope.schema.vocabulary import SimpleVocabulary
>>> dummy_vocabulary = SimpleVocabulary.fromValues([1,2,3])
>>> field.Choice(title=u"Test", source=dummy_vocabulary)
Traceback (most recent call last):
...
ValueError: Persistent fields do not support sources, only named vocabularies or vocabularies based on simple value sets.

或者指定对象词汇

>>> field.Choice(title=u"Test", vocabulary=dummy_vocabulary)
Traceback (most recent call last):
...
ValueError: Persistent fields only support named vocabularies or vocabularies based on simple value sets.

与其他字段一样,您也不能设置约束

>>> field.Choice(title=u"Test", values=[1,2,3], constraint=lambda x: True)
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint = lambda x: False
Traceback (most recent call last):
...
ValueError: Persistent fields does not support setting the `constraint` property

>>> f.constraint('ABC')
True

JSON 字段

集合字段描述了一个JSONField

>>> import plone.schema
>>> f = field.JSONField(title=u"Test")
>>> isinstance(f, plone.schema.JSONField)
True

>>> f.order
-1

IPersistentField 适配器

可以使用plone.registry字段factory中的适配器工厂将任何非持久字段适配到其相关的IPersistentField。这些在configure.zcml中设置,并在tests.py测试设置中显式注册。当然,也可以创建自定义适配器

>>> from plone.registry.interfaces import IPersistentField

>>> f = schema.TextLine(title=u"Test")
>>> IPersistentField.providedBy(f)
False

>>> p = IPersistentField(f)
>>> IPersistentField.providedBy(p)
True

>>> isinstance(p, field.TextLine)
True

默认情况下,不支持的字段类型无法适配

>>> f = schema.Object(title=u"Object", schema=IPersistentField)
>>> IPersistentField(f, None) is None
True

>>> f = schema.InterfaceField(title=u"Interface")
>>> IPersistentField(f, None) is None
True

适配后,将应用持久字段的规则:order属性始终为-1。不允许自定义约束,键和值类型也将适配到持久字段。如果这些约束中的任何一个无法满足,适配将失败。

对于约束,非持久值将被简单地忽略,并使用类中的默认方法。

>>> f = schema.TextLine(title=u"Test", constraint=lambda x: False)
>>> f.constraint
<function <lambda> at ...>

>>> p = IPersistentField(f)
>>> p.constraint
<bound method TextLine.constraint of <plone.registry.field.TextLine object at ...>>

类似地,将忽略order属性

>>> f.order > 0
True

>>> p.order
-1

如果可能,将适配键/值类型

>>> f = schema.Dict(title=u"Test",
...     key_type=schema.Id(title=u"Id"),
...     value_type=schema.TextLine(title=u"Value"))
>>> p = IPersistentField(f)
>>> p.key_type
<plone.registry.field.Id object at ...>

>>> p.value_type
<plone.registry.field.TextLine object at ...>

如果它们无法适配,将出现错误

>>> f = schema.Dict(title=u"Test",
...     key_type=schema.Id(title=u"Id"),
...     value_type=schema.Object(title=u"Value", schema=IPersistentField))
>>> p = IPersistentField(f)
Traceback (most recent call last):
...
TypeError: ('Could not adapt', <zope.schema._field.Dict object at ...>, <InterfaceClass plone.registry.interfaces.IPersistentField>)

>>> f = schema.Dict(title=u"Test",
...     key_type=schema.InterfaceField(title=u"Id"),
...     value_type=schema.TextLine(title=u"Value"))
>>> p = IPersistentField(f)
Traceback (most recent call last):
...
TypeError: ('Could not adapt', <zope.schema._field.Dict object at ...>, <InterfaceClass plone.registry.interfaces.IPersistentField>)

对于选择字段,存在额外的验证,这需要自定义适配器。这些确保词汇表要么以简单值的列表形式存储,要么作为命名词汇表存储。

>>> f = schema.Choice(title=u"Test", values=[1,2,3])
>>> p = IPersistentField(f)
>>> p.vocabulary
<zope.schema.vocabulary.SimpleVocabulary object at ...>
>>> p._values
[1, 2, 3]
>>> p.vocabularyName is None
True

>>> f = schema.Choice(title=u"Test", vocabulary='my.vocab')
>>> p = IPersistentField(f)
>>> p.vocabulary is None
True
>>> p._values is None
True
>>> p.vocabularyName
'my.vocab'

不允许复杂的词汇表或源

>>> from zope.schema.vocabulary import SimpleVocabulary
>>> dummy_vocabulary = SimpleVocabulary.fromItems([('a', 1), ('b', 2)])
>>> f = schema.Choice(title=u"Test", source=dummy_vocabulary)
>>> p = IPersistentField(f)
Traceback (most recent call last):
...
TypeError: ('Could not adapt', <zope.schema._field.Choice object at ...>, <InterfaceClass plone.registry.interfaces.IPersistentField>)


>>> f = schema.Choice(title=u"Test", vocabulary=dummy_vocabulary)
>>> p = IPersistentField(f)
Traceback (most recent call last):
...
TypeError: ('Could not adapt', <zope.schema._field.Choice object at ...>, <InterfaceClass plone.registry.interfaces.IPersistentField>)

变更日志

2.0.1 (2024-01-22)

内部

  • 更新配置文件。[plone开发者] (6e36bcc4, 7723aeaf)

2.0.0 (2023-04-26)

破坏性更改

  • 移除python 2.7兼容性。[gforcada] (#1)

内部

  • 更新配置文件。[plone开发者] (a864b30f)

1.2.1 (2021-06-14)

错误修复

  • 修复注册密钥验证正则表达式。[jensens] (#23)

1.2.0 (2021-04-23)

新特性

  • 允许plone.schema.JSONField存储在注册表中(作为字典类似物)。

    [sneridagh] (#719)

1.1.6 (2020-04-22)

错误修复

  • 小的打包更新。(#1)

1.1.5 (2018-12-14)

错误修复

  • 避免在Python 3.8上变成错误的弃用警告。[gforcada]

1.1.4 (2018-11-04)

错误修复

  • 适配测试以适应zope4中的更改对象字段。[pbauer]

1.1.3 (2018-06-22)

错误修复

  • 提高RecordsProxy.__iter__的性能,现在在核心Plone中作为requireJS配置的一部分调用得更多。[MatthewWilkes]

1.1.2 (2016-12-06)

错误修复

  • 修复测试以在Python 3.5上通过。[datakurre]

1.1.1 (2016-11-19)

错误修复

  • 修复从损坏的记录代理对象获取值时的无限递归。[tomgross]

1.1.0 (2016-07-05)

新特性

  • 为了使RecordsProxy成为良好的Zope公民,给它一个__parent__(即注册表)。这有助于在z3cform绑定程序和其他类似情况下,其中记录代理作为上下文使用。[jensens]

1.0.4 (2016-06-12)

修复

  • 更多的清理:PEP8,isort,可读性。[jensens]

1.0.3 (2016-02-26)

修复

  • 将已过时的 zope.testing.doctestunit 导入替换为stdlib中的 doctest 模块。[thet]

  • 清理:Pep8,utf8头,空白修复,可读性,ReST修复,文档风格等。[jensens]

1.0.2 (2014-09-11)

  • 选择字段构造与基于字符串选择的简单词汇表兼容,这些选择在构造时转换为值。这为plone.registry/plone.app.registry与plone.supermodel >= 1.2.5的集成提供兼容性。[seanupton]

1.0.1 (2013-01-13)

1.0 - 2011-05-13

  • 1.0版最终发布 [esteele]

  • 添加MANIFEST.in。[WouterVH]

1.0b5 - 2011-04-06

  • 通过forInterfacecollectionOfInterfacefactory参数使RecordsProxy类型可定制。[elro]

  • 向注册表中添加collectionOfInterface支持。[elro]

  • 修复了注册表忽略前缀的bug。[elro]

  • _Records的键/值/项目添加可选的最小/最大参数。[elro]

1.0b4 - 2011-02-04

  • 添加了对字段引用的支持,通过FieldRef类。有关详细信息,请参阅registry.txt。[optilude]

  • 更改内部持久结构以提高效率。API保持不变。旧注册表将在首次访问时迁移。警告:这可能会导致在使用注册表的第一次请求中出现“写时读”的情况。[optilude]

1.0b3 - 2011-01-03

  • forInterface添加前缀选项(如添加到registerInterface)[garbas]

1.0b2 - 2010-04-21

  • 添加了对Decimal字段的支持 [optilude]

  • 将registerInterface添加前缀选项,允许将接口用作一系列值的模板,而不是单次使用。[MatthewWilkes]

1.0b1 - 2009-08-02

  • 修复了Choice字段的bind()中的bug。[optilude]

1.0a2 - 2009-07-12

  • 将API方法和参数更改为mixedCase,以与Zope的其余部分保持一致。这是一个非向后兼容的更改。我们深表歉意,但现在或永不。[optilude]

    如果您发现代码中存在导入错误或未知的关键字参数,请将名称从foo_bar更改为fooBar,例如,for_interface()变为forInterface()。[optilude]

1.0a1 - 2009-04-17

  • 初始发布

项目详情


下载文件

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

源分发

plone.registry-2.0.1.tar.gz (48.8 kB 查看哈希值)

上传时间

构建分发

plone.registry-2.0.1-py3-none-any.whl (37.6 kB 查看哈希值)

上传时间 Python 3

由以下支持

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