doc/book/en/development/datamodel/definition.rst
changeset 4437 21f2e01fdd6a
parent 4430 0b6a069eb29e
child 4442 7bc0e4ed4109
equal deleted inserted replaced
4436:294e084f1263 4437:21f2e01fdd6a
     3 Yams *schema*
     3 Yams *schema*
     4 -------------
     4 -------------
     5 
     5 
     6 The **schema** is the core piece of a *CubicWeb* instance as it defines
     6 The **schema** is the core piece of a *CubicWeb* instance as it defines
     7 the handled data model. It is based on entity types that are either already
     7 the handled data model. It is based on entity types that are either already
     8 defined in the *CubicWeb* standard library; or more specific types, that
     8 defined in the *CubicWeb* standard library; or more specific types defined
     9 *CubicWeb* expects to find in one or more Python files under the directory
     9 in cubes. The schema for a cube is defined in a :file:schema.py file or in
    10 `schema`.
    10 one or more Python files under the :file:`schema` directory (python package).
    11 
    11 
    12 At this point, it is important to make clear the difference between
    12 At this point, it is important to make clear the difference between
    13 *relation type* and *relation definition*: a *relation type* is only a relation
    13 *relation type* and *relation definition*: a *relation type* is only a relation
    14 name with potentially other additionnal properties (see XXXX), whereas a
    14 name with potentially other additionnal properties (see below), whereas a
    15 *relation definition* is a complete triplet
    15 *relation definition* is a complete triplet
    16 "<subject entity type> <relation type> <object entity type>".
    16 "<subject entity type> <relation type> <object entity type>".
    17 A relation type could have been implied if none is related to a
    17 A relation type could have been implied if none is related to a
    18 relation definition of the schema.
    18 relation definition of the schema.
    19 
    19 
    20 
    20 Also, it should be clear that to properly handle data migration, an instance'schema
    21 All *CubicWeb* built-in types are available : `String`, `Int`, `Float`,
    21 is stored in the database, so the python schema file used to defined it are only readen
       
    22 when the instance is created or upgraded.
       
    23 
       
    24 The following built-in types are available : `String`, `Int`, `Float`,
    22 `Decimal`, `Boolean`, `Date`, `Datetime`, `Time`, `Interval`, `Byte`
    25 `Decimal`, `Boolean`, `Date`, `Datetime`, `Time`, `Interval`, `Byte`
    23 and `Password`.
    26 and `Password`.
    24 They are implicitely imported (as well as the special the function "_"
    27 
    25 for translation :ref:`internationalization`).
    28 You'll also have access to :ref:`CWBaseEntityTypes_:base cubicweb entitye types`.
    26 
    29 
    27 The instance schema is defined on all appobjects by a .schema class attribute set
    30 The instance schema is accessible through the .schema attribute of the
    28 on registration.  It's an instance of :class:`yams.schema.Schema`.
    31 `vregistry`.  It's an instance of :class:`cubicweb.schema.Schema`, which
       
    32 extends :class:`yams.schema.Schema`.
       
    33 
       
    34 :note:
       
    35   In previous yams versions, almost all classes where available without
       
    36   any import, but the should now be explicitely imported.
       
    37 
    29 
    38 
    30 Entity type
    39 Entity type
    31 ~~~~~~~~~~~
    40 ~~~~~~~~~~~
    32 It's an instance of :class:`yams.schema.EntitySchema`
    41 It's an instance of :class:`yams.schema.EntitySchema`. Each entity types has
    33 
    42 a set of attributes and relation and some permissions, defining who can add, read,
    34 XXX meta
    43 update or delete entities of this type.
    35 XXX permission
    44 
    36 XXX yams inheritance
    45 XXX yams inheritance
    37 
    46 
    38 Relation type
    47 Relation type
    39 ~~~~~~~~~~~~~
    48 ~~~~~~~~~~~~~
    40 It's an instance of :class:`yams.schema.RelationSchema`
    49 It's an instance of :class:`yams.schema.RelationSchema`. A relation type is simply
    41 
    50 a semantic definition of a kind of relationship that may occurs in your application.
    42 In addition to the permissions, the properties of the relation types
    51 
    43 (shared also by all definition of relation of this type) are :
    52 It's important to choose a good name, at least to avoid conflicts with some semantically
    44 
    53 different relation defined in other cubes (since we've no namespace yet).
       
    54 
       
    55 A relation type hold the following properties (which are hence shared between all
       
    56 relation definitions of that type):
    45 
    57 
    46 * `inlined` : boolean handling the physical optimization for archiving
    58 * `inlined` : boolean handling the physical optimization for archiving
    47   the relation in the subject entity table, instead of creating a specific
    59   the relation in the subject entity table, instead of creating a specific
    48   table for the relation. This applies to the relation when the cardinality
    60   table for the relation. This applies to relations where cardinality
    49   of subject->relation->object is 0..1 (`?`) or 1..1 (`1`)
    61   of subject->relation->object is 0..1 (`?`) or 1..1 (`1`) for *all* its relation
       
    62   definitions.
    50 
    63 
    51 * `symmetric` : boolean indicating that the relation is symmetrical, which
    64 * `symmetric` : boolean indicating that the relation is symmetrical, which
    52   means `X relation Y` implies `Y relation X`
    65   means that `X relation Y` implies `Y relation X`.
    53 
       
    54 XXX meta
       
    55 XXX permission
       
    56 
    66 
    57 
    67 
    58 Relation definition
    68 Relation definition
    59 ~~~~~~~~~~~~~~~~~~~
    69 ~~~~~~~~~~~~~~~~~~~
    60 Relation definition are represented in yams using an internal structure only exposed through the :mod:`api <yams.schema>`.
    70 It's an instance of :class:`yams.schema.RelationDefinition`. It is a complete triplet
       
    71 "<subject entity type> <relation type> <object entity type>".
    61 
    72 
    62 Properties
    73 Properties
    63 ``````````
    74 ``````````
    64 Properties defined below are accessible through the following api:
       
    65 
       
    66   RelationSchema.rproperties()
       
    67   RelationSchema.rproperty(subjtype, objtype, property name)
       
    68 
    75 
    69 * Optional properties for attributes and relations :
    76 * Optional properties for attributes and relations :
    70 
    77 
    71   - `description` : a string describing an attribute or a relation. By default
    78   - `description` : a string describing an attribute or a relation. By default
    72     this string will be used in the editing form of the entity, which means
    79     this string will be used in the editing form of the entity, which means
    86     * `1`: 1..1
    93     * `1`: 1..1
    87     * `?`: 0..1
    94     * `?`: 0..1
    88     * `+`: 1..n
    95     * `+`: 1..n
    89     * `*`: 0..n
    96     * `*`: 0..n
    90 
    97 
    91   - `meta` : boolean indicating that the relation is a meta-relation (false by
       
    92     default, will disappear in *CubicWeb* 3.5)
       
    93 
       
    94 * optional properties for attributes :
    98 * optional properties for attributes :
    95 
       
    96   - `required` : boolean indicating if the attribute is required (false by default)
       
    97 
    99 
    98   - `unique` : boolean indicating if the value of the attribute has to be unique
   100   - `unique` : boolean indicating if the value of the attribute has to be unique
    99     or not within all entities of the same type (false by default)
   101     or not within all entities of the same type (false by default)
   100 
   102 
   101   - `indexed` : boolean indicating if an index needs to be created for this
   103   - `indexed` : boolean indicating if an index needs to be created for this
   104     attribute.
   106     attribute.
   105 
   107 
   106   - `default` : default value of the attribute. In case of date types, the values
   108   - `default` : default value of the attribute. In case of date types, the values
   107     which could be used correspond to the RQL keywords `TODAY` and `NOW`.
   109     which could be used correspond to the RQL keywords `TODAY` and `NOW`.
   108 
   110 
   109   - `vocabulary` : specify static possible values of an attribute
       
   110 
       
   111 * optional properties of type `String` :
   111 * optional properties of type `String` :
   112 
   112 
   113   - `fulltextindexed` : boolean indicating if the attribute is part of
   113   - `fulltextindexed` : boolean indicating if the attribute is part of
   114     the full text index (false by default) (*applicable on the type `Byte`
   114     the full text index (false by default) (*applicable on the type `Byte`
   115     as well*)
   115     as well*)
   116 
   116 
   117   - `internationalizable` : boolean indicating if the value of the attribute
   117   - `internationalizable` : boolean indicating if the value of the attribute
   118     is internationalizable (false by default)
   118     is internationalizable (false by default)
   119 
       
   120   - `maxsize` : integer providing the maximum size of the string (no limit by default)
       
   121 
   119 
   122 * optional properties for relations :
   120 * optional properties for relations :
   123 
   121 
   124   - `composite` : string indicating that the subject (composite == 'subject')
   122   - `composite` : string indicating that the subject (composite == 'subject')
   125     is composed of the objects of the relations. For the opposite case (when
   123     is composed of the objects of the relations. For the opposite case (when
   126     the object is composed of the subjects of the relation), we just set
   124     the object is composed of the subjects of the relation), we just set
   127     'object' as value. The composition implies that when the relation
   125     'object' as value. The composition implies that when the relation
   128     is deleted (so when the composite is deleted), the composed are also deleted.
   126     is deleted (so when the composite is deleted, at least), the composed are also deleted.
   129 
   127 
   130   - `fti_container`: XXX feed me
   128   - `fti_container`: XXX feed me
   131 
   129 
   132 Constraints
   130 Constraints
   133 ```````````
   131 ```````````
   144   numeric types
   142   numeric types
   145 
   143 
   146 * `UniqueConstraint` : identical to "unique=True"
   144 * `UniqueConstraint` : identical to "unique=True"
   147 
   145 
   148 * `StaticVocabularyConstraint` : identical to "vocabulary=(...)"
   146 * `StaticVocabularyConstraint` : identical to "vocabulary=(...)"
       
   147 
       
   148 XXX Attribute, TODAY, NOW
   149 
   149 
   150 RQL Based Constraints
   150 RQL Based Constraints
   151 ......................
   151 ......................
   152 
   152 
   153 RQL based constraints may take three arguments. The first one is the ``WHERE``
   153 RQL based constraints may take three arguments. The first one is the ``WHERE``
   237   they own
   237   they own
   238 * the permissions of this group are only be checked on update/deletion
   238 * the permissions of this group are only be checked on update/deletion
   239   actions if all the other groups the user belongs does not provide
   239   actions if all the other groups the user belongs does not provide
   240   those permissions
   240   those permissions
   241 
   241 
   242 Setting permissions is done with the attribute `permissions` of entities and
   242 Setting permissions is done with the attribute `__permissions__` of entities and
   243 relation types. It defines a dictionary where the keys are the access types
   243 relation types. It defines a dictionary where the keys are the access types
   244 (action), and the values are the authorized groups or expressions.
   244 (action), and the values are the authorized groups or expressions.
   245 
   245 
   246 For an entity type, the possible actions are `read`, `add`, `update` and
   246 For an entity type, the possible actions are `read`, `add`, `update` and
   247 `delete`.
   247 `delete`.
   281 
   281 
   282 * the used expression corresponds to the WHERE statement of an RQL query
   282 * the used expression corresponds to the WHERE statement of an RQL query
   283 
   283 
   284 * in this expression, the variables X and U are pre-defined references
   284 * in this expression, the variables X and U are pre-defined references
   285   respectively on the current entity (on which the action is verified) and
   285   respectively on the current entity (on which the action is verified) and
   286   on the user who send the request
   286   on the user who send the._cwuest
   287 
   287 
   288 * it is possible to use, in this expression, a special relation
   288 * it is possible to use, in this expression, a special relation
   289   "has_<ACTION>_permission" where the subject is the user and the
   289   "has_<ACTION>_permission" where the subject is the user and the
   290   object is a any variable, meaning that the user needs to have
   290   object is a any variable, meaning that the user needs to have
   291   permission to execute the action <ACTION> on the entities related
   291   permission to execute the action <ACTION> on the entities related
   346 The class definition contains the description of attributes and relations
   346 The class definition contains the description of attributes and relations
   347 for the defined entity type.
   347 for the defined entity type.
   348 The class name corresponds to the entity type name. It is exepected to be
   348 The class name corresponds to the entity type name. It is exepected to be
   349 defined in the module ``mycube.schema``.
   349 defined in the module ``mycube.schema``.
   350 
   350 
   351 
   351 When defining a schema using python files, you may use the following shortcuts:
   352 For example ::
   352 
       
   353 - ._cwuired` : boolean indicating if the attribute is._cwuired, eg subject cardinality is '1'
       
   354 
       
   355 - `vocabulary` : specify static possible values of an attribute
       
   356 
       
   357 - `maxsize` : integer providing the maximum size of a string (no limit by default)
       
   358 
       
   359 For example:
       
   360 
       
   361 .. sourcecode:: python
   353 
   362 
   354   class Person(EntityType):
   363   class Person(EntityType):
   355     """A person with the properties and the relations necessary for my
   364     """A person with the properties and the relations necessary for my
   356     application"""
   365     application"""
   357 
   366 
   358     last_name = String(required=True, fulltextindexed=True)
   367     last_name = String._cwuired=True, fulltextindexed=True)
   359     first_name = String(required=True, fulltextindexed=True)
   368     first_name = String._cwuired=True, fulltextindexed=True)
   360     title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
   369     title = String(vocabulary=('Mr', 'Mrs', 'Miss'))
   361     date_of_birth = Date()
   370     date_of_birth = Date()
   362     works_for = SubjectRelation('Company', cardinality='?*')
   371     works_for = SubjectRelation('Company', cardinality='?*')
   363 
   372 
   364 
   373 
   427 
   436 
   428 In the case of simultaneous relations definitions, `subject` and `object`
   437 In the case of simultaneous relations definitions, `subject` and `object`
   429 can both be equal to the value of the first argument of `SubjectRelation`
   438 can both be equal to the value of the first argument of `SubjectRelation`
   430 and `ObjectRelation`.
   439 and `ObjectRelation`.
   431 
   440 
   432 When a relation is not inlined and not symmetrical, and it does not require
   441 When a relation is not inlined and not symmetrical, and it does not._cwuire
   433 specific permissions, its definition (by using `SubjectRelation` and
   442 specific permissions, its definition (by using `SubjectRelation` and
   434 `ObjectRelation`) is all we need.
   443 `ObjectRelation`) is all we need.
   435 
   444 
   436 
   445 
   437 Definition of permissions
   446 Definition of permissions
   438 ~~~~~~~~~~~~~~~~~~~~~~~~~~
   447 ~~~~~~~~~~~~~~~~~~~~~~~~~~
   439 
   448 
   440 In addition to that the entity type `CWPermission` from the standard library
   449 In addition to that the entity type `CWPermission` from the standard library
   441 allow to build very complex and dynamic security architecture. The schema of
   450 allow to build very complex and dynamic security architecture. The schema of
   442 this entity type is as follow : ::
   451 this entity type is as follow:
   443 
   452 
   444     class CWPermission(MetaEntityType):
   453 .. sourcecode:: python
       
   454 
       
   455     class CWPermission(EntityType):
   445 	"""entity type that may be used to construct some advanced security configuration
   456 	"""entity type that may be used to construct some advanced security configuration
   446 	"""
   457 	"""
   447 	name = String(required=True, indexed=True, internationalizable=True, maxsize=100)
   458 	name = String._cwuired=True, indexed=True, internationalizable=True, maxsize=100)
   448 	require_group = SubjectRelation('CWGroup', cardinality='+*',
   459 ._cwuire_group = SubjectRelation('CWGroup', cardinality='+*',
   449 					description=_('groups to which the permission is granted'))
   460 					description=_('groups to which the permission is granted'))
   450 	require_state = SubjectRelation('State',
   461 ._cwuire_state = SubjectRelation('State',
   451                                         description=_("entity's state in which the permission is applicable"))
   462                                         description=_("entity's state in which the permission is applicable"))
   452 	# can be used on any entity
   463 	# can be used on any entity
   453 	require_permission = ObjectRelation('**', cardinality='*1', composite='subject',
   464 ._cwuire_permission = ObjectRelation('**', cardinality='*1', composite='subject',
   454 					    description=_("link a permission to the entity. This "
   465 					    description=_("link a permission to the entity. This "
   455 							  "permission should be used in the security "
   466 							  "permission should be used in the security "
   456 							  "definition of the entity's type to be useful."))
   467 							  "definition of the entity's type to be useful."))
   457 
   468 
   458 
   469 
   459 Example of configuration ::
   470 Example of configuration:
       
   471 
       
   472 .. sourcecode:: python
   460 
   473 
   461 
   474 
   462     ...
   475     ...
   463 
   476 
   464     class Version(EntityType):
   477     class Version(EntityType):
   465 	"""a version is defining the content of a particular project's release"""
   478 	"""a version is defining the content of a particular project's release"""
   466 
   479 
   467 	permissions = {'read':   ('managers', 'users', 'guests',),
   480 	__permissions__ = {'read':   ('managers', 'users', 'guests',),
   468 		       'update': ('managers', 'logilab', 'owners',),
   481 		       'update': ('managers', 'logilab', 'owners',),
   469 		       'delete': ('managers', ),
   482 		       'delete': ('managers', ),
   470 		       'add':    ('managers', 'logilab',
   483 		       'add':    ('managers', 'logilab',
   471 				  ERQLExpression('X version_of PROJ, U in_group G,'
   484 				  ERQLExpression('X version_of PROJ, U in_group G,'
   472 						 'PROJ require_permission P, P name "add_version",'
   485 						 'PROJ._cwuire_permission P, P name "add_version",'
   473 						 'P require_group G'),)}
   486 						 'P._cwuire_group G'),)}
   474 
   487 
   475     ...
       
   476 
   488 
   477     class version_of(RelationType):
   489     class version_of(RelationType):
   478 	"""link a version to its project. A version is necessarily linked to one and only one project.
   490 	"""link a version to its project. A version is necessarily linked to one and only one project.
   479 	"""
   491 	"""
   480 	permissions = {'read':   ('managers', 'users', 'guests',),
   492 	__permissions__ = {'read':   ('managers', 'users', 'guests',),
   481 		       'delete': ('managers', ),
   493 		       'delete': ('managers', ),
   482 		       'add':    ('managers', 'logilab',
   494 		       'add':    ('managers', 'logilab',
   483 				  RRQLExpression('O require_permission P, P name "add_version",'
   495 				  RRQLExpression('O._cwuire_permission P, P name "add_version",'
   484 						 'U in_group G, P require_group G'),)
   496 						 'U in_group G, P._cwuire_group G'),)
   485 		       }
   497 		       }
   486 	inlined = True
   498 	inlined = True
   487 
   499 
   488 This configuration indicates that an entity `CWPermission` named
   500 This configuration indicates that an entity `CWPermission` named
   489 "add_version" can be associated to a project and provides rights to create
   501 "add_version" can be associated to a project and provides rights to create
   492 * in such case, we have to protect both the entity type "Version" and the relation
   504 * in such case, we have to protect both the entity type "Version" and the relation
   493   associating a version to a project ("version_of")
   505   associating a version to a project ("version_of")
   494 
   506 
   495 * because of the genericity of the entity type `CWPermission`, we have to execute
   507 * because of the genericity of the entity type `CWPermission`, we have to execute
   496   a unification with the groups and/or the states if necessary in the expression
   508   a unification with the groups and/or the states if necessary in the expression
   497   ("U in_group G, P require_group G" in the above example)
   509   ("U in_group G, P._cwuire_group G" in the above example)