3.1. 山药 图式¶
这个 图式 是A的核心部分 CubicWeb 实例定义并处理数据模型。它基于已在中定义的实体类型 Yams 以及 CubicWeb 标准库;或多维数据集中定义的更具体的类型。多维数据集的架构是在 schema python模块或包。
3.1.1. 概述¶
yams模式的核心思想离经典模式不远。 Entity-relationship 模型。但是当一个E/R模型(或 logical model )传统上,必须手动转换为较低级别的数据描述语言(如SQL create table 亚语言),也常被描述为 physical model ,不需要这样的步骤 Yams 和 CubicWeb .
这是因为除了高级逻辑 Yams 模型,一个使用 RQL 用于查询、插入、更新和删除数据的数据操作语言。 RQL 抽象的基础SQL数据库与 Yams 模式从物理布局中提取。SQL的变幻莫测是可以避免的。
作为额外的一点,这种抽象使构建或使用不同的后端变得相当舒适 RQL 应用查询。
So, as in the E/R formalism, the building blocks are entities
(实体类型), relationships
(关系类型,
关系定义) and attributes
(handled like relation
with Yams).
让我们详细说明一下E/R和 Yams :
所有关系都是二进制的,这意味着要表示非二进制关系,必须使用实体,
关系不支持属性(请参阅:http://www.cubicweb.org/ticket/341318),因此需要在需要时将其重新定义为实体,
所有实体都有一个 eid 作为其主键的属性(整数)(但可以在其他属性上声明唯一性)
阿尔索 Yams 支持以下概念:
实体继承(目前还处于实验阶段,完全没有文档记录);
关系类型:也就是说,可以在一组实体类型上建立关系(即 RelationType 和 RelationDefinition 以下)
终于 Yams 有一些自己的概念:
关系是定向的和二进制的,我们称左侧实体类型为 subject 右侧实体键入 object
注解
这个 Yams 架构在运行时通过的.schema属性可用。 vregistry .这是一个例子 cubicweb.schema.Schema
延伸 yams.schema.Schema
.
3.1.2. 实体类型¶
实体类型是的实例 yams.schema.EntitySchema
.每个实体类型都有一组属性和关系,以及一些权限,用于定义可以添加、读取、更新或删除此类型实体的人。
以下内置类型可用: String
, Int
, BigInt
, Float
, Decimal
, Boolean
, Date
, Datetime
, Time
, Interval
, Byte
和 Password
.它们只能用作其他实体类型的属性。
还有一个 RichString 类型:
这个 __unique_together__
类属性是属性名或内联关系的元组列表。对于每个元组,CubicWeb确保组合的唯一性。例如:
class State(EntityType):
__unique_together__ = [('name', 'state_of')]
name = String(required=True)
state_of = SubjectRelation('Workflow', cardinality='1*',
composite='object', inlined=True)
您可以在中找到更多基本实体类型 库中预先定义的实体 .
3.1.3. 关系类型¶
关系类型是的实例 yams.schema.RelationSchema
.关系类型只是应用程序中可能出现的一种关系的语义定义。
它可以被零个、一个或多个关系定义引用。
选择一个好的名称很重要,至少要避免与其他多维数据集中定义的某些语义不同的关系发生冲突(因为这些名称只有一个共享名称空间)。
关系类型包含以下属性(因此在该类型的所有关系定义之间共享这些属性):
inlined :布尔值,处理在主题实体表中存档关系的物理优化,而不是为关系创建特定表。这适用于主题->关系->对象的基数为0..1的关系。 (? )或1..1 (1 为 all 它的关系定义。
symmetric :布尔值,表示关系是对称的,这意味着 X relation Y 暗示 Y relation X .
3.1.4. 关系定义¶
关系定义是 yams.schema.RelationDefinition
.它是一个完整的三元组“<subject entity type><relation type><object entity type>”。
在创建该类的新实例时, RelationType
如果需要,可以动态创建实例。
3.1.4.1. 属性¶
此处枚举关系定义的可用属性。有几种属性,因为有些关系定义实际上是属性定义,而另一些则不是。
某些属性可能是完全可选的,其他属性可能具有默认值。
属性和关系的公共属性:
description :描述属性或关系的Unicode字符串。默认情况下,该字符串将以实体的编辑形式使用,这意味着它应该帮助最终用户,并且应该由函数进行标记。 _ 适当国际化。
constraints: a list of conditions/constraints that the relation has to satisfy (c.f. Constraints)
cardinality :两个字符的字符串,指定关系的基数。第一个字符定义主题关系的基数,第二个字符定义对象关系的基数。当一个关系可以有多个主题或对象时,基数适用于所有对象,而不是一对一的基础(因此它必须是一致的…)。默认值为“**”。可能的值来自正则表达式语法:
1 :1..1
? :0..1
+ :1..n
* :0..n
属性属性:
unique :布尔值,指示属性值在同一类型的所有实体中是否必须唯一(默认为false)
indexed :布尔值,指示是否需要在数据库中为此属性创建索引(默认为false)。只有当您知道必须对该属性的值执行多次搜索时,这才有用。
default :属性的默认值。对于日期类型,可以使用的值对应于rql关键字 TODAY 和 NOW .
metadata: Is also accepted as an argument of the attribute contructor. It is not really an attribute property. see Metadata 有关详细信息。
的属性 String 属性:
fulltextindexed :布尔值,指示属性是否为全文索引的一部分(默认为false)( applicable on the type `Byte` as well )
internationalizable :布尔值,指示属性值是否可国际化(默认为false)
关系属性:
composite :表示主题(composite='subject')由关系的对象组成的字符串。对于相反的情况(当对象由关系的主题组成时),我们只将“对象”设置为值。组合意味着当关系被删除时(至少当组合被删除时),组合也被删除。
fulltext_container :字符串,指示是否应使用关系一端的实体全文索引来查找另一端的实体。可能的值为“subject”或“object”。例如,“使用电子邮件”关系将该属性设置为“主题”,因为执行全文搜索时,人们希望使用电子邮件地址查找实体,而不是表示电子邮件地址的实体。
3.1.4.2. 约束条件¶
默认情况下,可用的约束类型为:
3.1.4.2.1. 一般约束¶
SizeConstraint :允许指定字符串的最小和/或最大大小(一般为 maxsize )
BoundaryConstraint :允许指定数值类型和日期的最小值和/或最大值
from yams.constraints import BoundaryConstraint, TODAY, NOW, Attribute
class DatedEntity(EntityType):
start = Date(constraints=[BoundaryConstraint('>=', TODAY())])
end = Date(constraints=[BoundaryConstraint('>=', Attribute('start'))])
class Before(EntityType);
last_time = DateTime(constraints=[BoundaryConstraint('<=', NOW())])
IntervalBoundConstraint :允许指定包含值的间隔
class Node(EntityType):
latitude = Float(constraints=[IntervalBoundConstraint(-90, +90)])
UniqueConstraint :与“唯一=真”相同
StaticVocabularyConstraint :与“词汇=…”相同
约束可以依赖于固定值(90,日期(2015,3,23))或变量。在第二种情况下,Yams可以处理:
Attribute :与其他属性的值进行比较。
TODAY :与当前日期比较。
NOW :与当前日期时间进行比较。
3.1.4.2.2. 基于RQL的约束¶
基于RQL的约束可能有三个参数。第一个是 WHERE
约束使用的RQL查询的子句。第二个论点 mainvars
是 Any
查询的子句。默认情况下,这包括 S 为关系的主题保留 O 对于对象。其他变量可以使用 mainvars
.该参数需要一个字符串,所有变量的名称由空格分隔。最后一个, msg
,是约束失败时显示的错误消息。由于rqVocabularyConstraint从不失败,第三个参数不可用。
RQLConstraint :允许指定主题和/或关系对象必须满足的RQL查询。在这个查询中,变量 S 和 O 为关系主题和对象实体保留。
RQLVocabularyConstraint :与以前的约束类型类似,只是它不表示“强”约束,这意味着它只用于限制编辑窗体下拉菜单中列出的值,但不阻止选择其他实体。
RQLUniqueConstraint :允许指定RQL查询,以确保属性在特定上下文中是唯一的。查询必须 从未 返回多个要满足的结果。在这个查询中,变量 S 为关系主题实体保留。其他变量应使用第二个构造函数参数(mainvars)指定。此约束类型应在以下情况下使用: __unique_together__ 不合适。
3.1.5. 安全模式¶
的安全模型 CubicWeb 基于 Access Control List .主要原则是:
用户和用户组
用户至少属于一组用户
权限 (read , update , create , delete )
权限分配给组(而不是用户)
为了 CubicWeb 特别地:
我们在实体/关系模式级别关联权限
默认组为: managers , users 和 guests
用户属于 users 组
存在一个名为 owners 我们只能与之联系 delete 和 update 权限
我们无法将用户添加到 owners 分组,根据所属对象的上下文将它们隐式添加到其中。
仅在上检查此组的权限 update /` delete`actions如果用户所属的所有其他组都不提供这些权限
通过class属性设置权限 __permissions__ 实体类型和关系定义。该属性的值是一个字典,其中键是访问类型(操作),值是授权的组或rql表达式。
对于实体类型,可能的操作是 read , add , update 和 delete .
对于关系,可能的操作是 read , add 和 delete .
对于属性,可能的操作是 read , add 和 update ,它们是对实体类型权限的细化。
注解
默认情况下,实体类型属性的权限等同于实体类型本身的权限。
可以提供强于或宽于实体类型权限的自定义属性权限。
在所有属性都被授予自定义权限的情况下,不会检查实体类型权限,除非 delete 行动。
对于每个访问类型,一个元组指示授权组的名称和/或一个或多个RQL表达式,以满足授予访问的要求。如果用户位于所列的某个组中或满足某个RQL条件,则提供访问权。
3.1.5.1. 默认权限¶
的默认权限 EntityType
是:
__permissions__ = {
'read': ('managers', 'users', 'guests',),
'update': ('managers', 'owners',),
'delete': ('managers', 'owners'),
'add': ('managers', 'users',)
}
关系的默认权限为:
__permissions__ = {'read': ('managers', 'users', 'guests',),
'delete': ('managers', 'users'),
'add': ('managers', 'users',)}
属性的默认权限为:
__permissions__ = {'read': ('managers', 'users', 'guests',),
'add': ('managers', ERQLExpression('U has_add_permission X'),
'update': ('managers', ERQLExpression('U has_update_permission X')),}
注解
属性的默认权限在语法上并不等同于实体类型的默认权限,但RQL表达式通过委托给实体类型权限来工作。
3.1.5.2. 标准用户组¶
guests
users
managers
owners :实体所有者对应的虚拟组。这只能用于操作 update 和 delete 实体类型的。
如果在多维数据集的预创建脚本中定义了特定组,也可以使用它们 (migration/precreate.py
)。在后创建脚本或更高版本中定义组使其不可用于安全目的(在本例中,是指 sync_schema_props_perms 命令必须在cubicWeb shell中发出)。
3.1.5.3. 使用rql表达式获得写权限¶
可以定义rql表达式以提供更新权限 (add , delete 和 update )关于实体类型/关系定义。RQL表达式是一条查询(对应于RQL查询的WHERE语句),如果表达式返回某些结果,则认为它满足要求。它们不能用于 read 许可。
要在实体类型权限中使用rql表达式,请执行以下操作:
你必须使用课堂
ERQLExpression
在这个表达式中,变量 X 和 U 分别是当前实体(验证操作的实体)和发送请求的用户上的预定义引用。
对于关系类型上的rql表达式,原则是相同的,除了以下内容:
你必须使用课堂
RRQLExpression
而不是ERQLExpression
在表达式中,变量 S , O 和 U 分别是对当前关系(对其操作进行验证)的主题和对象以及执行查询的用户的预定义引用。
要定义实体属性(非最终关系)的安全性,必须使用类 ERQLExpression
在哪儿 X 表示属性所属的实体。
在这些表达式中可以使用特殊关系 has_<ACTION>_permission 其中主题是用户(如“u”),对象是表示实体(通常是“x”)的任何变量。 ERQLExpression
,'s'或'o'输入 RRQLExpression
,这意味着用户需要有权对该变量表示的实体执行action<action>。建议尽可能使用此功能,因为它简化了非常复杂的安全定义和升级。
class my_relation(RelationDefinition):
__permissions__ = {'read': ('managers', 'users'),
'add': ('managers', RRQLExpression('U has_update_permission S')),
'delete': ('managers', RRQLExpression('U has_update_permission S'))
}
在上面的示例中,将允许用户添加/删除 my_relation 如果他有 update 关于关系主题的许可。
注解
有可能, use of an RQL expression to add an entity or a relation 可能会导致用户界面出现问题,因为如果表达式使用实体或关系来创建,则在实际添加实体之前我们无法验证权限(请注意,这对于RQL服务器来说根本不是问题,因为权限检查是在在创造之后)。在这种情况下,权限检查方法(cubicWebEntitySchema.check perm和has perm)可以指示用户在获得权限时不允许创建此实体。为了弥补这个问题,在这种情况下,通常需要使用反映模式权限的操作,但要正确检查权限,以便只有在可能的情况下才显示出来。
3.1.5.4. 使用RQL表达式获得阅读权¶
原则相同,但有以下限制:
不能将rql表达式用于 read 关系和属性的许可,
你不能用特殊的 has_<ACTION>_permission rql表达式中的关系。
3.1.5.5. 关于写权限检查的重要说明¶
写入权限(例如“添加”、“更新”、“删除”)已签入核心挂钩。
当权限被选中时,根据它是实体还是关系,以及关系是否是属性关系,略有不同)。重要的是要理解,因为根据检查权限的时间,RQL表达式返回的值可能会更改,因此是否授予权限。
以下是当前规则:
在提交时检查添加/更新实体及其属性的权限
删除实体的权限在“删除实体前”挂钩中签入。
添加关系的权限选中:
如果关系类型在 BEFORE_ADD_RELATIONS 设置
如果关系类型在 ON_COMMIT_ADD_RELATIONS 设置
“after-add-u relationship”钩子中的else(默认)
删除关系的权限在“删除关系前”挂钩中签入。
最后,但不是最不重要的,记住从钩子发出的查询和操作在默认情况下是“不安全的”,例如没有读或写安全检查。
见 cubicweb.hooks.security
了解更多详细信息。
3.2. 派生属性和关系¶
注解
TODO 检查文档整个章节的组织结构
CubicWeb提供了 查询 使用所谓的数据 计算 关系和属性。这些是 seen 通过RQL请求作为普通属性和关系,但实际上是从其他属性和关系派生出来的。在第一部分中,我们将非正式地回顾两个典型的用例。然后我们将看到如何在模式中使用计算属性和关系。最后,我们将考虑其实现的各个重要方面以及对其使用的影响。
3.2.1. 激励用例¶
3.2.1.1. 计算关系¶
经常出现的情况是,一个人必须代表一个三元关系,或一个家庭的关系。例如,在展览目录的上下文中,您可能希望链接所有 贡献者 到 work 他们贡献了,但是这个贡献可以是 插图画家 , 作者 , 表演者 ,…
描述实体关系模式中此类信息的经典方法是 重新整理 关系,即将关系转换为实体。在我们的示例中,模式将具有 贡献 用于表示贡献关系族的实体类型。
class ArtWork(EntityType):
name = String()
...
class Person(EntityType):
name = String()
...
class Contribution(EntityType):
contributor = SubjectRelation('Person', cardinality='1*', inlined=True)
manifestation = SubjectRelation('ArtWork')
role = SubjectRelation('Role')
class Role(EntityType):
name = String()
但是,为了查询Illustrator I
一部作品 W
必须写:
Any I, W WHERE C is Contribution, C contributor I, C manifestation W,
C role R, R name 'illustrator'
然而,我们希望能够简单地写:
Any I, W WHERE I illustrator_of W
这正是计算关系所允许的。
3.2.1.2. 计算(或合成)属性¶
假设用一个简单的模式来描述公司中的员工,人们可能会对公司为其所有员工支付的工资总额感兴趣。必须写:
Any C, SUM(SA) GROUPBY S WHERE E works_for C, E salary SA
而简单地写是最方便的:
Any C, TS WHERE C total_salary TS
这也是计算属性所提供的。
3.2.2. 使用计算属性和关系¶
3.2.2.1. 计算关系¶
在上述情况下,我们将定义 计算关系 illustrator_of
在架构中:
class illustrator_of(ComputedRelation):
rule = ('C is Contribution, C contributor S, C manifestation O,'
'C role R, R name "illustrator"')
您会注意到:
这个
S
和O
rql变量隐式地标识定义的计算关系的主题和对象,类似于rrqlExpression中发生的情况。根据规则推断出可能的主题和对象实体类型;
计算关系定义始终为空 add 和 删除 权限
read 可以定义权限,权限来自重写规则中使用的关系 不考虑 ;
在 ComputedRelation 描述、权限和规则旁边的子类(例如,无基数、复合等)。 BadSchemaDefinition 在尝试指定其他属性时引发;
“set”和“delete”rql查询中不能使用计算关系 (BadQuery 引发异常)。
注意:事实上 add 和 删除 权限是 空的 即使对于管理者,也希望使自动用户界面不尝试编辑它们。
3.2.2.2. 计算(或合成)属性¶
在上述情况下,我们将定义 计算属性 total_salary
上 Company
架构中的实体类型依据:
class Company(EntityType):
name = String()
total_salary = Int(formula='Any SUM(SA) GROUPBY E WHERE P works_for X, E salary SA')
这个
X
rql变量隐式标识包含计算属性的实体,类似于erqlExpression中发生的情况;根据公式推断出的类型将与声明的类型进行检查,并且 BadSchemaDefinition 如果不匹配则被提升;
计算属性始终为空 更新 权限
BadSchemaDefinition 在尝试设置“更新”权限时引发;
可以定义“读取”权限,有关公式的权限 不考虑 ;
其他属性的属性(内联,…)可以定义为普通属性;
与计算关系类似,计算属性不能用于“set”和“delete”rql查询 (BadQuery 引发异常)。
3.2.3. API与实现¶
3.2.3.1. 数据后端中的表示¶
计算关系在SQL表级别没有直接表示。相反,每次发出查询时,都会重写该查询,以用其等效定义替换计算关系,并以通常的方式执行结果重写查询。
相反,计算属性在其主机实体类型的表中表示为一列,就像普通属性一样。它们的值通过钩子系统(在大多数RDBMS中也称为触发器)保持最新的定义,该系统在修改它们所依赖的关系和属性时重新计算它们。
3.2.3.2. 山药原料药¶
当通过 山药原料药 (在 schema.py
文件)计算的属性和关系表示如下:
- 关系
这个
yams.RelationSchema
班有新的rule
将规则保存为字符串的属性。如果设置了此属性,则不能设置所有其他属性。- 属性
新的财产
formula
添加到类中yams.RelationDefinitionSchema
使用新的关键字参数进行alomngformula
在初始值设定项上。
3.2.3.3. 迁移¶
迁移将按照下面的数组中的总结进行处理。
计算的类型 |
计算属性 |
|
---|---|---|
添加 |
|
|
修改 (规则或公式) |
|
|
德尔 |
|
|
3.3. 使用yams定义模式¶
3.3.1. 实体类型定义¶
实体类型由继承自 yams.buildobjs.EntityType
.类定义包含已定义实体类型的属性和关系的描述。类名对应于实体类型名。它应该在模块中定义。 mycube.schema
.
- 关于模式定义的说明
代码在
mycube.schema
不打算被处决。上面提到的EntityType类与上一章中描述的EntitySchema类不同。EntityType是一个帮助器类,用于简化实体定义。Yams将处理EntityType类并从这些类定义创建EntitySchema实例。对关系也有类似的操纵。
使用python文件定义架构时,可以使用以下快捷方式:
required :布尔值,指示是否需要属性,ed subject基数为“1”
vocabulary :指定属性的静态可能值
maxsize :提供字符串最大大小的整数(默认无限制)
例如:
class Person(EntityType):
"""A person with the properties and the relations necessary for my
application"""
last_name = String(required=True, fulltextindexed=True)
first_name = String(required=True, fulltextindexed=True)
title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
date_of_birth = Date()
works_for = SubjectRelation('Company', cardinality='?*')
上面描述的实体定义了类型字符串、姓氏、名字和标题三个属性,出生日期的类型日期属性和连接 Person 到另一个类型的实体 Company 通过语义 works_for .
- 命名约定
实体类名称必须以大写字母开头。常用的用法是
CamelCase
姓名。属性和关系名称必须以小写字母开头。常用的用法是
underscore_separated_words
.允许以单个下划线开头的属性和关系名称表示某种程度上“受保护”或“私有”属性。在任何情况下,以“cw”或“cw”开头的标识符都保留给框架内部使用。
使用另一个属性的名称作为前缀的某些属性被视为元数据。例如,如果EntityType同时具有
data
和data_format
属性,data_format
将视图视为format
的元数据data
.稍后cw_attr_metadata()
方法将允许您获取与属性相关的元数据。只有三个有效的元数据名称:format
,encoding
和name
.
python属性的名称对应于属性的名称或中的关系 CubicWeb 应用。
架构中的属性定义如下:
attr_name = AttrType(*properties, metadata={})
在哪里?
AttrType :是中列出的类型之一 EntityType,
properties: is a list of the attribute needs to satisfy (see Properties 更多详细信息)
metadata: is a dictionary of meta attributes related to
attr_name
. Dictionary keys are the name of the meta attribute. Dictionary values attributes objects (like the content ofAttrType
). For each entry of the metadata dictionary a<attr_name>_<key> = <value>
attribute is automaticaly added to the EntityType. see Metadata 有关有效密钥的详细信息。
---
在构建架构时
可以使用该属性 meta 将实体类型标记为 meta (例如,用于描述/分类其他实体)
Note :如果您最终 if 在实体的定义中,这可能意味着您需要两个独立的实体来实现 ITree 接口并从中获取结果 .children() 任何一个实体所关心的。
3.3.2. 关系的定义¶
关系由python类继承定义。 RelationType .类的名称对应于类型的名称。然后,类包含对这种关系类型属性的描述,还可以包含主题的字符串和对象的字符串。这允许创建关联关系的新定义(以便类可以具有该关系的定义属性),例如:
class locked_by(RelationType):
"""relation on all entities indicating that they are locked"""
inlined = True
cardinality = '?*'
subject = '*'
object = 'CWUser'
如果提供,则 subject 和 object 属性表示与关系类型相关的各种关系定义的主题和对象。这些属性的允许值为:
与实体类型对应的字符串
对应于多个实体类型的字符串元组
“*”特殊字符串,表示所有类型的实体
当一个关系不是内联的和非对称的,并且不需要特定的权限时,可以使用 SubjectRelation EntityType类中的属性。第一个论点 SubjectRelation 为关系的对象提供实体类型。
- 命名约定
尽管这种定义关系的方法使用了一个python类,但是前面定义的命名约定优先于框架中使用的pep8约定:关系类型类名使用
underscore_separated_words
.- 历史记录
历史上有可能使用 ObjectRelation 它定义了一个相反方向的关系。此功能已弃用,因此不应在新编写的代码中使用。
- 未来折旧说明
在更遥远的将来,SubjectRelation快捷方式很可能会被弃用,而倾向于RelationType声明,它在可重用多维数据集的上下文中提供了一些优势。
3.3.3. 处理架构更改¶
另外,要正确处理数据迁移,应该清楚的是,实例的模式存储在数据库中,因此用于定义它的python模式文件只有在创建或升级实例时才被读取。