为Zope 3的关系字段框架。
项目描述
z3c.relationfield
简介
此包实现了一个新的模式字段 Relation,以及用于存储实际关系的 RelationValue 对象。它可以使用 zc.relation 基础设施对这些关系进行索引,并通过使用这些索引可以有效地回答关于关系的各种问题。
此外,包 z3c.relationfieldui 还提供了一个小部件来编辑和显示 Relation 字段。
设置
z3c.relationfield.Relation 是一个用于表达关系的模式字段。让我们定义一个使用关系字段的模式 IItem。
>>> from z3c.relationfield import Relation
>>> from zope.interface import Interface
>>> class IItem(Interface):
... rel = Relation(title=u"Relation")
我们还定义了一个类 Item,它实现了 IItem 和特殊接口 z3c.relationfield.interfaces.IHasRelations。
>>> from z3c.relationfield.interfaces import IHasRelations
>>> from persistent import Persistent
>>> from zope.interface import implementer
>>> @implementer(IItem, IHasRelations)
... class Item(Persistent):
...
... def __init__(self):
... self.rel = None
IHasRelations 标记接口是必要的,以便对 Item 上的关系进行编目(例如,当它们被放入容器中或从容器中移除时)。实际上,它是 IHasIncomingRelations 和 IHasOutgoingRelations 的组合,这对于我们想要支持双向关系来说是合适的。
最后,我们需要一个测试应用程序。
>>> from zope.site.site import SiteManagerContainer
>>> from zope.container.btree import BTreeContainer
>>> class TestApp(SiteManagerContainer, BTreeContainer):
... pass
我们设置了测试应用程序。
>>> from ZODB.MappingStorage import DB
>>> db = DB()
>>> conn = db.open()
>>> root = conn.root()['root'] = TestApp()
>>> conn.add(root)
我们确保这是当前站点,这样我们就可以在其中查找本地实用程序等。通常这由 Zope 的遍历机制自动完成。
>>> from zope.site.site import LocalSiteManager
>>> root.setSiteManager(LocalSiteManager(root))
>>> from zope.component.hooks import setSite
>>> setSite(root)
为了使此站点与 z3c.relationship 一起工作,我们需要设置两个实用程序。首先是一个 IIntIds,它跟踪 ZODB 中对象的唯一标识符。
>>> from zope.intid import IntIds
>>> from zope.intid.interfaces import IIntIds
>>> root['intids'] = intids = IntIds()
>>> sm = root.getSiteManager()
>>> sm.registerUtility(intids, provided=IIntIds)
其次是一个关系目录,它实际上索引关系。
>>> from z3c.relationfield import RelationCatalog
>>> from zc.relation.interfaces import ICatalog
>>> root['catalog'] = catalog = RelationCatalog()
>>> sm.registerUtility(catalog, provided=ICatalog)
使用关系字段
我们将向我们的应用程序添加一个项目 a。
>>> root['a'] = Item()
所有项目,包括我们刚刚创建的项目,都应该具有唯一的 int id,因为这需要将它们链接起来。
>>> from zope import component
>>> from zope.intid.interfaces import IIntIds
>>> intids = component.getUtility(IIntIds)
>>> a_id = intids.getId(root['a'])
>>> a_id >= 0
True
当前的关系是 None。
>>> root['a'].rel is None
True
现在我们可以创建一个项目 b,它通过其 int id 链接到项目 a。
>>> from z3c.relationfield import RelationValue
>>> b = Item()
>>> b.rel = RelationValue(a_id)
现在我们将 b 对象存储在容器中,这将设置其关系(因为将触发 IObjectAddedEvent)。
>>> root['b'] = b
让我们检查这个关系。首先,我们将检查指向对象(‘b’)的哪个属性是这个关系所指向的。
>>> root['b'].rel.from_attribute
'rel'
我们可以请求它所指向的对象。
>>> to_object = root['b'].rel.to_object
>>> to_object.__name__
'a'
我们还可以获取正在指向的对象;由于我们提供了 IHasRelations 接口,事件系统负责设置这一点。
>>> from_object = root['b'].rel.from_object
>>> from_object.__name__
'b'
此对象也称为 __parent__;同样,事件系统负责设置这一点。
>>> parent_object = root['b'].rel.__parent__
>>> parent_object is from_object
True
关系还知道指向对象和被指向对象的接口。
>>> from pprint import pprint
>>> pprint(sorted(root['b'].rel.from_interfaces))
[<InterfaceClass zope.location.interfaces.IContained>,
<InterfaceClass z3c.relationfield.interfaces.IHasRelations>,
<InterfaceClass builtins.IItem>,
<InterfaceClass persistent.interfaces.IPersistent>]
>>> pprint(sorted(root['b'].rel.to_interfaces))
[<InterfaceClass zope.location.interfaces.IContained>,
<InterfaceClass z3c.relationfield.interfaces.IHasRelations>,
<InterfaceClass builtins.IItem>,
<InterfaceClass persistent.interfaces.IPersistent>]
我们还可以以扁平形式获取接口。
>>> pprint(sorted(root['b'].rel.from_interfaces_flattened))
[<InterfaceClass zope.location.interfaces.IContained>,
<InterfaceClass z3c.relationfield.interfaces.IHasIncomingRelations>,
<InterfaceClass z3c.relationfield.interfaces.IHasOutgoingRelations>,
<InterfaceClass z3c.relationfield.interfaces.IHasRelations>,
<InterfaceClass builtins.IItem>,
<InterfaceClass zope.location.interfaces.ILocation>,
<InterfaceClass persistent.interfaces.IPersistent>,
<InterfaceClass zope.interface.Interface>]
>>> pprint(sorted(root['b'].rel.to_interfaces_flattened))
[<InterfaceClass zope.location.interfaces.IContained>,
<InterfaceClass z3c.relationfield.interfaces.IHasIncomingRelations>,
<InterfaceClass z3c.relationfield.interfaces.IHasOutgoingRelations>,
<InterfaceClass z3c.relationfield.interfaces.IHasRelations>,
<InterfaceClass builtins.IItem>,
<InterfaceClass zope.location.interfaces.ILocation>,
<InterfaceClass persistent.interfaces.IPersistent>,
<InterfaceClass zope.interface.Interface>]
路径
我们还可以获取关系的路径(从它所指向的地方到它所指向的地方)。该路径应该是人类可读的参考,适用于序列化。为了使用路径,我们首先需要设置一个 IObjectPath 实用程序。
由于在这个示例中我们只将对象放置在一个单个扁平根容器中,此演示中的路径可以非常简单:只是我们指向的对象的名称。在更复杂的应用程序中,路径通常是斜杠分隔的路径,例如 /foo/bar。
>>> from zope.interface import Interface
>>> from zope.interface import implementer
>>> from z3c.objpath.interfaces import IObjectPath
>>> @implementer(IObjectPath)
... class ObjectPath(object):
...
... def path(self, obj):
... return obj.__name__
... def resolve(self, path):
... try:
... return root[path]
... except KeyError:
... raise ValueError("Cannot resolve path %s" % path)
>>> from zope.component import getGlobalSiteManager
>>> gsm = getGlobalSiteManager()
>>> op = ObjectPath()
>>> gsm.registerUtility(op)
在此之后,我们可以获取关系指向的对象的路径。
>>> root['b'].rel.to_path
'a'
我们还可以获取正在指向的对象的路径。
>>> root['b'].rel.from_path
'b'
比较和排序关系
让我们创建一些 RelationValue 对象并比较它们。
>>> rel_to_a = RelationValue(a_id)
>>> b_id = intids.getId(root['b'])
>>> rel_to_b = RelationValue(b_id)
>>> rel_to_a == rel_to_b
False
当然,关系等于自身。
>>> rel_to_a == rel_to_a
True
存储的关系等于尚未存储的关系。
>>> root['b'].rel == rel_to_a
True
我们还可以对关系进行排序。
>>> expected = [('', 'a'), ('', 'b'), ('b', 'a')]
>>> observed = [(rel.from_path, rel.to_path) for rel in
... sorted([root['b'].rel, rel_to_a, rel_to_b])]
>>> expected == observed
True
关系查询
现在我们已经设置并索引了 a 和 b 之间的关系,我们可以使用关系目录发出查询。让我们首先获取目录。
>>> from zc.relation.interfaces import ICatalog
>>> catalog = component.getUtility(ICatalog)
让我们查询目录,了解从 b 到 a 的关系。
>>> l = sorted(catalog.findRelations({'to_id': intids.getId(root['a'])}))
>>> l
[<...RelationValue object at ...>]
再次观察这个关系对象。我们确实找到了正确的关系。
>>> rel = l[0]
>>> rel.from_object.__name__
'b'
>>> rel.to_object.__name__
'a'
>>> rel.from_path
'b'
>>> rel.to_path
'a'
查询到 b 的关系将会得到一个空列表,因为没有设置这样的关系。
>>> sorted(catalog.findRelations({'to_id': intids.getId(root['b'])}))
[]
我们还可以发出更具体的查询,限制在用于关系字段的属性和由相关对象提供的接口上。在这里,我们寻找存储在对象属性 rel 中,并且从一个具有接口 IItem 的对象指向另一个具有接口 IItem 的对象的全部关系。
>>> sorted(catalog.findRelations({
... 'to_id': intids.getId(root['a']),
... 'from_attribute': 'rel',
... 'from_interfaces_flattened': IItem,
... 'to_interfaces_flattened': IItem}))
[<...RelationValue object at ...>]
没有存储其他属性的任何关系。
>>> sorted(catalog.findRelations({
... 'to_id': intids.getId(root['a']),
... 'from_attribute': 'foo'}))
[]
也没有存储我们将在这里介绍的新接口的关系。
>>> class IFoo(IItem):
... pass
>>> sorted(catalog.findRelations({
... 'to_id': intids.getId(root['a']),
... 'from_interfaces_flattened': IItem,
... 'to_interfaces_flattened': IFoo}))
[]
更改关系
让我们创建一个新的对象 c。
>>> root['c'] = Item()
>>> c_id = intids.getId(root['c'])
目前没有任何东西指向 c。
>>> sorted(catalog.findRelations({'to_id': c_id}))
[]
我们目前有一个从 b 到 a 的关系。
>>> sorted(catalog.findRelations({'to_id': intids.getId(root['a'])}))
[<...RelationValue object at ...>]
我们可以更改这个关系,使其指向新对象 c。
>>> root['b'].rel = RelationValue(c_id)
我们需要发送一个 IObjectModifiedEvent,让目录知道我们已经更改了关系。
>>> from zope.event import notify
>>> from zope.lifecycleevent import ObjectModifiedEvent
>>> notify(ObjectModifiedEvent(root['b']))
现在我们应该找到一个从 b 到 c 的单一关系。
>>> sorted(catalog.findRelations({'to_id': c_id}))
[<...RelationValue object at ...>]
到 a 的关系现在应该消失了。
>>> sorted(catalog.findRelations({'to_id': intids.getId(root['a'])}))
[]
如果我们在一个非模式字段中存储关系,它应该持久化 ObjectModifiedEvent。
>>> from z3c.relationfield.event import _setRelation
>>> _setRelation(root['b'], 'my-fancy-relation', rel_to_a)
>>> sorted(catalog.findRelations({'to_id': intids.getId(root['a'])}))
[<...RelationValue object at ...>]
>>> notify(ObjectModifiedEvent(root['b']))
>>> rel = sorted(catalog.findRelations({'to_id': intids.getId(root['a'])}))
>>> rel
[<...RelationValue object at ...>]
>>> catalog.unindex(rel[0])
删除关系
我们目前有一个从 b 到 c 的关系。
>>> sorted(catalog.findRelations({'to_id': c_id}))
[<...RelationValue object at ...>]
我们可以通过将其设置为 None 来清理从 b 到 c 的现有关系。
>>> root['b'].rel = None
我们需要发送一个 IObjectModifiedEvent,让目录知道我们已经更改了关系。
>>> notify(ObjectModifiedEvent(root['b']))
将 b 上的关系设置为 None 应该从关系目录中删除该关系,因此我们不应该再找到它。
>>> sorted(catalog.findRelations({'to_id': intids.getId(root['c'])}))
[]
让我们重新建立已删除的关系。
>>> root['b'].rel = RelationValue(c_id)
>>> notify(ObjectModifiedEvent(root['b']))
>>> sorted(catalog.findRelations({'to_id': c_id}))
[<...RelationValue object at ...>]
复制带有关系的对象
让我们复制一个带有关系的对象。
>>> from zope.copypastemove.interfaces import IObjectCopier
>>> IObjectCopier(root['b']).copyTo(root)
'b-2'
>>> 'b-2' in root
True
现在可以找到两个指向 c 的关系,一个来自原始对象,另一个来自副本。
>>> l = sorted(catalog.findRelations({'to_id': c_id}))
>>> len(l)
2
>>> l[0].from_path
'b'
>>> l[1].from_path
'b-2'
关系是可排序的
默认情况下,关系根据关系名称、关系所在对象的路径以及关系所指向对象的路径的组合进行排序。
让我们查询所有当前可用的关系并对其进行排序。
>>> l = sorted(catalog.findRelations())
>>> len(l)
2
>>> l[0].from_attribute
'rel'
>>> l[1].from_attribute
'rel'
>>> l[0].from_path
'b'
>>> l[1].from_path
'b-2'
删除带有关系的对象
我们将再次删除 b-2。其关系应自动从目录中删除。
>>> del root['b-2']
>>> l = sorted(catalog.findRelations({'to_id': c_id}))
>>> len(l)
1
>>> l[0].from_path
'b'
中断关系
我们目前有一个从 b 到 c 的关系。
>>> sorted(catalog.findRelations({'to_id': c_id}))
[<...RelationValue object at ...>]
我们没有断开的关系。
>>> sorted(catalog.findRelations({'to_id': None}))
[]
这个关系没有断开。
>>> b.rel.isBroken()
False
我们现在将通过删除 c 来断开这个关系。
>>> del root['c']
这个关系现在已断开。
>>> b.rel.isBroken()
True
原始关系仍然有一个 to_path。
>>> b.rel.to_path
'c'
然而,它是断开的,因为没有 to_object。
>>> b.rel.to_object is None
True
to_id 也消失了。
>>> b.rel.to_id is None
True
我们不能以这种方式在目录中找到断开的关系,因为它不再指向 c_id。
>>> sorted(catalog.findRelations({'to_id': c_id}))
[]
然而,我们可以通过搜索具有 to_id 为 None 的关系来找到它。
>>> sorted(catalog.findRelations({'to_id': None}))
[<...RelationValue object at ...>]
断开的关系不等于 None(这是一个错误)。
>>> b.rel == None
False
RelationChoice
一个 RelationChoice 字段与一个普通的 Relation 字段非常相似,但可以用来渲染一个允许选择的项目特殊小部件。
我们将首先演示一个 RelationChoice 字段与一个 Relation 字段本身具有相同的效果
>>> from z3c.relationfield import RelationChoice
>>> class IChoiceItem(Interface):
... rel = RelationChoice(title=u"Relation", values=[])
>>> @implementer(IChoiceItem, IHasRelations)
... class ChoiceItem(Persistent):
...
... def __init__(self):
... self.rel = None
让我们创建一个对象来指向这个关系
>>> root['some_object'] = Item()
>>> some_object_id = intids.getId(root['some_object'])
然后,我们建立这个关系
- .. 代码块:
python
>>> choice_item = ChoiceItem() >>> choice_item.rel = RelationValue(some_object_id) >>> root['choice_item'] = choice_item
现在我们可以查询这个关系了
>>> l = sorted(catalog.findRelations({'to_id': some_object_id}))
>>> l
[<...RelationValue object at ...>]
关系列表
现在让我们尝试使用 RelationList 字段,它可以用来维护关系列表
>>> from z3c.relationfield import RelationList
>>> class IMultiItem(Interface):
... rel = RelationList(title=u"Relation")
我们还定义了一个 MultiItem 类,它实现了 IMultiItem 以及特殊的 z3c.relationfield.interfaces.IHasRelations 接口
>>> @implementer(IMultiItem, IHasRelations)
... class MultiItem(Persistent):
...
... def __init__(self):
... self.rel = None
我们设置了一些对象,然后在这些对象之间建立关系
>>> root['multi1'] = MultiItem()
>>> root['multi2'] = MultiItem()
>>> root['multi3'] = MultiItem()
让我们从 multi1 创建到 multi2 和 multi3 的关系
>>> multi1_id = intids.getId(root['multi1'])
>>> multi2_id = intids.getId(root['multi2'])
>>> multi3_id = intids.getId(root['multi3'])
>>> root['multi1'].rel = [RelationValue(multi2_id),
... RelationValue(multi3_id)]
我们需要通知已经修改了 ObjectModifiedEvent
>>> notify(ObjectModifiedEvent(root['multi1']))
现在这个已经设置好了,让我们验证是否可以在目录中找到合适的关系
>>> len(list(catalog.findRelations({'to_id': multi2_id})))
1
>>> len(list(catalog.findRelations({'to_id': multi3_id})))
1
>>> len(list(catalog.findRelations({'from_id': multi1_id})))
2
临时关系
如果我们有一个导入程序,从外部源(如XML文件)导入关系,那么可能我们读取的关系指向的对象还不存在,因为它尚未被导入。我们为此情况提供了一个特殊的 TemporaryRelationValue。一个 TemporaryRelationValue 只包含它指向的路径,但尚未解析。让我们在一个新对象中使用 TemporaryRelationValue,创建一个指向 a 的关系
>>> from z3c.relationfield import TemporaryRelationValue
>>> root['d'] = Item()
>>> root['d'].rel = TemporaryRelationValue('a')
修改事件实际上并没有将这个关系编入目录
>>> before = sorted(catalog.findRelations({'to_id': a_id}))
>>> notify(ObjectModifiedEvent(root['d']))
>>> after = sorted(catalog.findRelations({'to_id': a_id}))
>>> len(before) == len(after)
True
现在我们将 d 上的所有临时关系转换为真实的关系
>>> from z3c.relationfield import realize_relations
>>> realize_relations(root['d'])
>>> notify(ObjectModifiedEvent(root['d']))
现在我们可以看到真实的关系对象
>>> root['d'].rel
<...RelationValue object at ...>
关系现在也会出现在目录中
>>> after2 = sorted(catalog.findRelations({'to_id': a_id}))
>>> len(after2) > len(before)
True
临时关系值也与 RelationList 对象一起工作
>>> root['multi_temp'] = MultiItem()
>>> root['multi_temp'].rel = [TemporaryRelationValue('a')]
让我们将其转换为真实的关系
>>> realize_relations(root['multi_temp'])
>>> notify(ObjectModifiedEvent(root['multi_temp']))
再次,当我们查看它时,我们可以看到真实的关系对象
>>> root['multi_temp'].rel
[<...RelationValue object at ...>]
现在我们将在目录中看到这个新关系
>>> after3 = sorted(catalog.findRelations({'to_id': a_id}))
>>> len(after3) > len(after2)
True
损坏的临时关系
让我们创建另一个临时关系,这次是一个无法解析的损坏的关系
>>> root['e'] = Item()
>>> root['e'].rel = TemporaryRelationValue('nonexistent')
让我们尝试实现这个关系
>>> realize_relations(root['e'])
我们最终得到了一个损坏的关系
>>> root['e'].rel.isBroken()
True
它指向一个不存在的路径
>>> root['e'].rel.to_path
'nonexistent'
建立关系目录
此包提供了一个初始化了用于查询 RelationValue 对象的常用索引集的 RelationCatalog。默认索引包括 from_id、to_id、from_attribute、from_interfaces_flattened 和 to_interfaces_flattened。
有时需要定义自定义索引或使用少于默认的索引。可以使用包含键 element 和 kwargs 的字典列表初始化 zc.relationfield.index.RelationCatalog 类,这些键将被传递给 RelationCatalog 的 addValueIndex 方法。通常,element 是 IRelationValue 上的属性,如 IRelationValue['from_id']。然而,如果使用了具有额外字段的 IRelationValue 子类,则可以将这些字段添加到这里作为索引。
变更
1.1 (2023-08-17)
考虑没有来源的 RelationValue 为损坏。 [ksuess]
1.0 (2023-02-22)
破坏性变更
停止支持 Python 2.7、3.5、3.6。
新功能
添加对 Python 3.7、3.8、3.9、3.10、3.11 的支持。
0.9.0 (2019-09-15)
新功能
提供 IRelationBrokenEvent,以便在订阅 IObjectModifiedEvent 时能够区分事件 [vangheem]
0.8.0 (2019-02-13)
新功能
地址 仍然错误地使用 BTrees,搞乱了人们修改接口,允许第三方软件定义使用哪些索引。[jensens]
错误修复
修复 tests.py 中的 DeprecationWarnings。[jensens]
0.7.1 (2018-11-08)
Python 3 兼容性:使用实现者装饰器并修复排序。[ale-rt]
Python 3 兼容性:使 RelationValue 可哈希。[sallner]
将 README.txt 重命名为 README.rst,将 CHANGES.txt 重命名为 CHANGES.rst。[thet]
更新 buildout / travis 配置。[tomgross]
修复当关系不是作为类属性存储时修改关系会被清除的问题。用例请参阅 https://github.com/plone/Products.CMFPlone/issues/2384。[tomgross]
0.7 (2015-03-13)
移除对 zope.app.* 的依赖。[davisagli]
0.6.3 (2014-04-15)
移除对 grok 的依赖。[pbauer, jensens]
0.6.2 (2012-12-06)
更新测试设置和测试,使其与依赖包的当前版本一起运行,因此也可以在 Python 2.6 下运行。
添加缺失的(测试)依赖。
将 __neq__ 方法重命名为 __ne__,因为 __neq__ 不是 != 处理器的正确内置名称。
0.6.1 (2009-10-11)
修复损坏的发布版本。
0.6 (2009-10-11)
确保在构建字段时,关系列表的 value_type 不会被覆盖为 'None'。
0.5 (2009-06-30)
将 lxml 和 schema2xml 依赖项移动到 [xml] 额外依赖项中,这样人们就可以使用此包而无需安装 lxml,它仍在一些平台上引起问题。如果 z3c.schema2xml 和 lxml 无法导入,则不会定义相关适配器,但其他一切仍然正常工作。
订阅到 IIntIdAddedEvent 而不是 IObjectAddedEvent,以防止由于订阅者排序错误而导致的错误。
0.4.3 (2009-06-04)
添加缺少的 lxml 依赖。
0.4.2 (2009-04-22)
防止在缺少工具或对象未实现 IContained 时事件失败。
0.4.1 (2009-02-12)
不要处理尚未具有父对象的对象的 IObjectModified 事件。实际上也没有必要这样做,因为这些对象无法有出向关系索引。
0.4 (2009-02-10)
引入一个 RelationChoice 字段,它类似于 schema.Choice,但跟踪关系。与源(如由 z3c.relationfieldui 提供的 RelationSourceFactory 创建的源)结合使用,这可以用于创建关系的下拉选择。
阐明比较和排序 RelationValue 对象的方式,以更好地支持选择支持。
0.3.2 (2009-01-21)
当关系损坏时,正确地重新编目事物。
0.3.1 (2009-01-20)
基于 (from_attribute, from_path, to_path) 元组引入合理的排序顺序。
关系现在永远不会与 None 进行比较。
0.3 (2009-01-19)
引入两个新的接口:IHasOutgoingRelations 和 IHasIncomingRelations。 IHasOutgoingRelations 应由实际上设置了关系的对象提供,以便它们可以正确编目。 IHasIncomingRelations 应设置在可以关联的对象上,以便可以正确跟踪损坏的关系。IHasRelations 现在扩展了这两个接口,因此如果您在对象上提供这些接口,则该对象可以具有出向关系和入向关系。
改进损坏关系支持。现在,当您断开关系(通过删除关系目标)时,to_id 和 to_object 变为 None。然而,to_path 将保持关系最后指向的路径。也可以创建 TemporaryRelation 对象,这些对象在实现时是损坏的关系。
您还可以通过在关系上调用 isBroken 来检查损坏状态。
顶层函数 create_relation 的签名已更改。它原本接受要创建关系的对象,但现在应该接收路径(以 IObjectPath 术语表示)。如果路径无法解析,create_relation 现在将创建一个损坏的关系对象。
0.2 (2009-01-08)
添加了对 RelationList 字段的支持。这允许用户维护一个 RelationValue 对象的列表,这些对象将像常规 Relation 字段一样被编目。
取消了对 IRelationInfo 适配器的需求。只需定义一个执行相同工作的 create_relation 函数。
在查找对象上的关系时,如果找不到这些关系,则应更加宽容(只需跳过它们) - 这可能发生在模式更改时。
0.1 (2008-12-05)
首次公开发布。
下载
项目详情
下载文件
下载适合您平台的文件。如果您不确定要选择哪个,请了解更多关于 安装包 的信息。
源分发
构建分发
z3c.relationfield-1.1.tar.gz 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | c218e01834c3374f6dffa2b755d1cf99ba157da66bf4c4c30c0e7bf17a09fa91 |
|
MD5 | 8af45c0dfc5a93bf869bdaf185c96678 |
|
BLAKE2b-256 | d07ec0e83a59f45ad7296b5dd3c2062e5e72cfd03e71b6d4c7491d278ae6e2fa |
z3c.relationfield-1.1-py3-none-any.whl 的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 1c09b4d93f023d12bc83719f2d19dbbc577d20a266876642cbbe2cfcb6c08ccb |
|
MD5 | 825ca5d1afaeb93cd3e0ac948cb2d8a7 |
|
BLAKE2b-256 | ec7eda5f2ef08213c03a42a59d039a5d56b1777f32a36766e51b4c7070d22d67 |