.. -*- coding: utf-8 -*-
Data as objects
===============
In this chapter, we will introduce the objects that are used to handle
the data stored in the database.
Class `Entity` and `AnyEntity`
------------------------------
To provide a specific behavior for each entity, we have to define
a class inheriting from `cubicweb.entities.AnyEntity`. In general, we
define this class in a module of `mycube.entities` package of an application
so that it will be available on both server and client side.
The class `AnyEntity` is loaded dynamically from the class `Entity`
(`cubciweb.common.entity`). We define a sub-class to add methods or to
specialize the handling of a given entity type
Descriptors are added when classes are registered in order to initialize the class
according to its schema:
* we can access the defined attributes in the schema thanks to the attributes of
the same name on instances (typed value)
* we can access the defined relations in the schema thanks to the relations of
the same name on instances (entities instances list)
The methods defined for `AnyEntity` or `Entity` are the following ones:
* `has_eid()`, returns true is the entity has an definitive eid (e.g. not in the
creation process)
* `check_perm(action)`, checks if the user has the permission to execute the
requested action on the entity
:Formatting and output generation:
* `view(vid, **kwargs)`, applies the given view to the entity
* `absolute_url(**kwargs)`, returns an absolute URL to access the primary view
of an entity
* `rest_path()`, returns a relative REST URL to get the entity
* `format(attr)`, returns the format (MIME type) of the field given un parameter
* `printable_value(attr, value=_marker, attrtype=None, format='text/html')`,
returns a string enabling the display of an attribute value in a given format
(the value is automatically recovered if necessary)
* `display_name(form='')`, returns a string to display the entity type by
specifying the preferred form (`plural` for a plural form)
:Data handling:
* `as_rset()`, converts the entity into an equivalent result set simulating the
request `Any X WHERE X eid _eid_`
* `complete(skip_bytes=True)`, executes a request that recovers in one time
all the missing attributes of an entity
* `get_value(name)`, returns the value associated to the attribute name given
in parameter
* `related(rtype, x='subject', limit=None, entities=False)`, returns a list
of entities related to the current entity by the relation given in parameter
* `unrelated(rtype, targettype, x='subject', limit=None)`, returns a result set
corresponding to the entities not related to the current entity by the
relation given in parameter and satisfying its constraints
* `set_attributes(**kwargs)`, updates the attributes list with the corresponding
values given named parameters
* `copy_relations(ceid)`, copies the relations of the entities having the eid
given in the parameters on the current entity
* `last_modified(view)`, returns the date the object has been modified
(used by HTTP cache handling)
* `delete()` allows to delete the entity
:Standard meta-data (Dublin Core):
* `dc_title()`, returns a unicode string corresponding to the meta-data
`Title` (used by default the first attribute non-meta of the entity
schema)
* `dc_long_title()`, same as dc_title but can return a more
detailled title
* `dc_description(format='text/plain')`, returns a unicode string
corresponding to the meta-data `Description` (look for a description
attribute by default)
* `dc_authors()`, returns a unicode string corresponding to the meta-data
`Authors` (owners by default)
* `dc_date(date_format=None)`, returns a unicode string corresponding to
the meta-data `Date` (update date by default)
:Vocabulary control on relations:
* `vocabulary(rtype, x='subject', limit=None)`, called by the
editing views, it returns a list of couples (label, eid) of entities
that could be related to the entity by the relation `rtype`
* `subject_relation_vocabulary(rtype, limit=None)`, called internally
by `vocabulary` in the case of a subject relation
* `object_relation_vocabulary(rtype, limit=None)`, called internally
by `vocabulary` in the case of an object relation
* `relation_vocabulary(rtype, targettype, x, limit=None)`, called
internally by `subject_relation_vocabulary` and `object_relation_vocabulary`
Class `TreeMixIn`
-----------------
This class provides a tree interface. This mixin has to be inherited
explicitly and configured using the tree_attribute, parent_target and
children_target class attribute to benefit from this default implementation.
This class provides the following methods:
* `different_type_children(entities=True)`, returns children entities
of different type as this entity. According to the `entities` parameter,
returns entity objects (if entity=True) or the equivalent result set.
* `same_type_children(entities=True)`, returns children entities of
the same type as this entity. According to the `entities` parameter,
return entity objects (if entity=True) or the equivalent result set.
* `iterchildren( _done=None)`, iters on the children of the entity.
* `prefixiter( _done=None)`
* `path()`, returns the list of eids from the root object to this object.
* `iterparents()`, iters on the parents of the entity.
* `notification_references(view)`, used to control References field
of email send on notification for this entity. `view` is the notification view.
Should return a list of eids which can be used to generate message ids
of previously sent email.
`TreeMixIn` implements also the ITree interface (``cubicweb.interfaces``):
* `parent()`, returns the parent entity if any, else None (e.g. if we are on the
root)
* `children(entities=True, sametype=False)`, returns children entities
according to the `entities` parameter, return entity objects or the
equivalent result set.
* `children_rql()`, returns the RQL query corresponding to the children
of the entity.
* `is_leaf()`, returns True if the entity does not have any children.
* `is_root()`, returns True if the entity does not have any parent.
* `root()`, returns the root object of the tree representation of
the entity and its related entities.
Example of use
``````````````
Imagine you defined three types of entities in your schema, and they
relates to each others as follows in ``schema.py``::
class Entity1(EntityType):
title = String()
is_related_to = SubjectRelation('Entity2', 'subject')
class Entity2(EntityType):
title = String()
belongs_to = SubjectRelation('Entity3', 'subject')
class Entity3(EntityType):
name = String()
You would like to create a view that applies to both entity types
`Entity1` and `Entity2` and which lists the entities they are related to.
That means when you view `Entity1` you want to list all `Entity2`, and
when you view `Entity2` you want to list all `Entity3`.
In ``entities.py``::
class Entity1(TreeMixIn, AnyEntity):
id = 'Entity1'
__implements__ = AnyEntity.__implements__ + (ITree,)
__rtags__ = {('is_related_to', 'Entity2', 'object'): 'link'}
tree_attribute = 'is_related_to'
def children(self, entities=True):
return self.different_type_children(entities)
class Entity2(TreeMixIn, AnyEntity):
id = 'Entity2'
__implements__ = AnyEntity.__implements__ + (ITree,)
__rtags__ = {('belongs_to', 'Entity3', 'object'): 'link'}
tree_attribute = 'belongs_to'
def children(self, entities=True):
return self.different_type_children(entities)
Once this is done, you can define your common view as follows::
class E1E2CommonView(baseviews.PrimaryView):
accepts = ('Entity11, 'Entity2')
def render_entity_relations(self, entity, siderelations):
self.wview('list', entity.children(entities=False))
*rtags*
-------
*rtags* allow to specify certain behaviors of relations relative to a given
entity type (see later). They are defined on the entity class by the attribute
`rtags` which is a dictionary with as keys the triplets ::
<relation type>, <target entity type>, <context position ("subject" ou "object")>
and as values a `set` or a tuple of markers defining the properties that
apply to this relation.
It is possible to simplify this dictionary:
* if we want to specifiy a single marker, it is not necessary to
use a tuple as value, the marker by itself (character string)
is enough
* if we only care about a single type of relation and not about the target
and the context position (or when this one is not ambigous), we can simply
use the name of the relation type as key
* if we want a marker to apply independently from the target entity type,
we have to use the string `*` as target entity type
Please note that this dictionary is *treated at the time the class is created*.
It is automatically merged with the parent class(es) (no need to copy the
dictionary from the parent class to modify it). Also, modifying it after the
class is created will not have any effect...
.. include:: B0031-define-entities.en.txt