应用程序设置注册表(如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 基本类型,它就是受支持的;同样适用于字段的属性。
因此
像 Object、InterfaceField 等字段是不受支持的。
不支持自定义 constraint 方法。
将始终将 order 属性设置为 -1。
对于选择字段,仅支持 命名词汇表:您无法引用特定的 源 或 源绑定器。
Dict、List、Tuple、Set 和 Frozenset 的 key_type 和 value_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
带有初始值的记录创建
我们可以通过以下方式一次性简洁地创建记录:
创建字段
创建记录并设置其值
将其分配给注册表
如下所示
>>> 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。它有两个字段:sender 和 smtp_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 标记,并有两个额外的属性: interface 和 fieldName
>>> 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.formlib 或 z3c.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 记录上发生的任何记录事件。当然,还可以注册针对例如 IRecordModifiedEvent 或 IRecordRemovedEvent 的更专业的事件处理器。请注意,无法重新分配 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_type 和 value_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属性会根据值动态构建一个词汇表,并且vocabularyName为None
>>> 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
通过forInterface和collectionOfInterface的factory参数使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 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 4a19201727e3665f98ca742c408f9dab27b36a2fc48f4e9a0ea3864df9eebb8c |
|
MD5 | 2a27e1a5665cef562d24d2f37aac1cf9 |
|
BLAKE2b-256 | 33f5011bf18de3ab917eb1dd67b9c44b220a37d19a92f56d9da26d260a291f37 |
plone.registry-2.0.1-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 34108d1ead452002a5d5d8ddf8813dfe111da53b8cedeb56332e555afd73e888 |
|
MD5 | df5577dc4fa9fca095c343b92f53bb67 |
|
BLAKE2b-256 | 436a8cae3a4bd75ad7b8e3f8dfee31600b44b3c162d72efd7dcab436fdf1df61 |