doc/book/en/B0030-data-as-objects.en.txt
changeset 1808 aa09e20dd8c0
parent 1693 49075f57cf2c
parent 1807 6d541c610165
child 1810 e95e876be17c
equal deleted inserted replaced
1693:49075f57cf2c 1808:aa09e20dd8c0
     1 .. -*- coding: utf-8 -*-
       
     2 
       
     3 
       
     4 Data as objects
       
     5 ===============
       
     6 
       
     7 In this chapter, we will introduce the objects that are used to handle
       
     8 the data stored in the database.
       
     9 
       
    10 Class `Entity` and `AnyEntity`
       
    11 ------------------------------
       
    12 
       
    13 To provide a specific behavior for each entity, we have to define
       
    14 a class inheriting from `cubicweb.entities.AnyEntity`. In general, we
       
    15 define this class in a module of `mycube.entities` package of an application
       
    16 so that it will be available on both server and client side.
       
    17 
       
    18 The class `AnyEntity` is loaded dynamically from the class `Entity` 
       
    19 (`cubciweb.common.entity`). We define a sub-class to add methods or to
       
    20 specialize the handling of a given entity type
       
    21 
       
    22 Descriptors are added when classes are registered in order to initialize the class
       
    23 according to its schema:
       
    24 
       
    25 * we can access the defined attributes in the schema thanks to the attributes of
       
    26   the same name on instances (typed value)
       
    27 
       
    28 * we can access the defined relations in the schema thanks to the relations of
       
    29   the same name on instances (entities instances list)
       
    30 
       
    31 The methods defined for `AnyEntity` or `Entity` are the following ones:
       
    32 
       
    33 * `has_eid()`, returns true is the entity has an definitive eid (e.g. not in the
       
    34   creation process)
       
    35         
       
    36 * `check_perm(action)`, checks if the user has the permission to execute the
       
    37   requested action on the entity
       
    38 
       
    39 :Formatting and output generation:
       
    40 
       
    41   * `view(vid, **kwargs)`, applies the given view to the entity
       
    42 
       
    43   * `absolute_url(**kwargs)`, returns an absolute URL to access the primary view
       
    44     of an entity
       
    45     
       
    46   * `rest_path()`, returns a relative REST URL to get the entity
       
    47 
       
    48   * `format(attr)`, returns the format (MIME type) of the field given un parameter
       
    49 
       
    50   * `printable_value(attr, value=_marker, attrtype=None, format='text/html')`, 
       
    51     returns a string enabling the display of an attribute value in a given format
       
    52     (the value is automatically recovered if necessary)
       
    53 
       
    54   * `display_name(form='')`, returns a string to display the entity type by 
       
    55     specifying the preferred form (`plural` for a plural form)
       
    56 
       
    57 :Data handling:
       
    58 
       
    59   * `as_rset()`, converts the entity into an equivalent result set simulating the 
       
    60      request `Any X WHERE X eid _eid_`
       
    61 
       
    62   * `complete(skip_bytes=True)`, executes a request that recovers in one time
       
    63     all the missing attributes of an entity
       
    64 
       
    65   * `get_value(name)`, returns the value associated to the attribute name given
       
    66     in parameter
       
    67 
       
    68   * `related(rtype, x='subject', limit=None, entities=False)`, returns a list
       
    69     of entities related to the current entity by the relation given in parameter
       
    70 
       
    71   * `unrelated(rtype, targettype, x='subject', limit=None)`, returns a result set
       
    72     corresponding to the entities not related to the current entity by the
       
    73     relation given in parameter and satisfying its constraints
       
    74 
       
    75   * `set_attributes(**kwargs)`, updates the attributes list with the corresponding
       
    76     values given named parameters
       
    77 
       
    78   * `copy_relations(ceid)`, copies the relations of the entities having the eid
       
    79     given in the parameters on the current entity
       
    80 
       
    81   * `last_modified(view)`, returns the date the object has been modified
       
    82     (used by HTTP cache handling)
       
    83 
       
    84   * `delete()` allows to delete the entity
       
    85   
       
    86 :Standard meta-data (Dublin Core):
       
    87 
       
    88   * `dc_title()`, returns a unicode string corresponding to the meta-data
       
    89     `Title` (used by default the first attribute non-meta of the entity
       
    90     schema)
       
    91 
       
    92   * `dc_long_title()`, same as dc_title but can return a more
       
    93     detailled title
       
    94 
       
    95   * `dc_description(format='text/plain')`, returns a unicode string 
       
    96     corresponding to the meta-data `Description` (look for a description
       
    97     attribute by default)
       
    98 
       
    99   * `dc_authors()`, returns a unicode string corresponding to the meta-data 
       
   100     `Authors` (owners by default)
       
   101 
       
   102   * `dc_date(date_format=None)`, returns a unicode string corresponding to 
       
   103     the meta-data `Date` (update date by default)
       
   104             
       
   105 :Vocabulary control on relations:
       
   106 
       
   107   * `vocabulary(rtype, x='subject', limit=None)`, called by the
       
   108     editing views, it returns a list of couples (label, eid) of entities
       
   109     that could be related to the entity by the relation `rtype`
       
   110   * `subject_relation_vocabulary(rtype, limit=None)`, called internally 
       
   111     by  `vocabulary` in the case of a subject relation
       
   112   * `object_relation_vocabulary(rtype, limit=None)`, called internally 
       
   113     by  `vocabulary` in the case of an object relation
       
   114   * `relation_vocabulary(rtype, targettype, x, limit=None)`, called
       
   115     internally by `subject_relation_vocabulary` and `object_relation_vocabulary`
       
   116 
       
   117 Class `TreeMixIn`
       
   118 -----------------
       
   119 
       
   120 This class provides a tree interface. This mixin has to be inherited 
       
   121 explicitly and configured using the tree_attribute, parent_target and 
       
   122 children_target class attribute to benefit from this default implementation.
       
   123 
       
   124 This class provides the following methods:
       
   125 
       
   126   * `different_type_children(entities=True)`, returns children entities
       
   127     of different type as this entity. According to the `entities` parameter, 
       
   128     returns entity objects (if entity=True) or the equivalent result set.
       
   129 
       
   130   * `same_type_children(entities=True)`, returns children entities of 
       
   131     the same type as this entity. According to the `entities` parameter, 
       
   132     return entity objects (if entity=True) or the equivalent result set.
       
   133   
       
   134   * `iterchildren( _done=None)`, iters on the children of the entity.
       
   135   
       
   136   * `prefixiter( _done=None)`
       
   137   
       
   138   * `path()`, returns the list of eids from the root object to this object.
       
   139   
       
   140   * `iterparents()`, iters on the parents of the entity.
       
   141   
       
   142   * `notification_references(view)`, used to control References field 
       
   143     of email send on notification for this entity. `view` is the notification view.
       
   144     Should return a list of eids which can be used to generate message ids
       
   145     of previously sent email.
       
   146 
       
   147 `TreeMixIn` implements also the ITree interface (``cubicweb.interfaces``):
       
   148 
       
   149   * `parent()`, returns the parent entity if any, else None (e.g. if we are on the
       
   150     root)
       
   151 
       
   152   * `children(entities=True, sametype=False)`, returns children entities
       
   153     according to the `entities` parameter, return entity objects or the
       
   154     equivalent result set.
       
   155 
       
   156   * `children_rql()`, returns the RQL query corresponding to the children
       
   157     of the entity.
       
   158 
       
   159   * `is_leaf()`, returns True if the entity does not have any children.
       
   160 
       
   161   * `is_root()`, returns True if the entity does not have any parent.
       
   162 
       
   163   * `root()`, returns the root object of the tree representation of
       
   164     the entity and its related entities.
       
   165 
       
   166 Example of use
       
   167 ``````````````
       
   168 
       
   169 Imagine you defined three types of entities in your schema, and they
       
   170 relates to each others as follows in ``schema.py``::
       
   171 
       
   172   class Entity1(EntityType):
       
   173       title = String()
       
   174       is_related_to = SubjectRelation('Entity2', 'subject')
       
   175 
       
   176   class Entity2(EntityType):
       
   177       title = String()
       
   178       belongs_to = SubjectRelation('Entity3', 'subject')
       
   179 
       
   180   class Entity3(EntityType):
       
   181       name = String()
       
   182 
       
   183 You would like to create a view that applies to both entity types
       
   184 `Entity1` and `Entity2` and which lists the entities they are related to.
       
   185 That means when you view `Entity1` you want to list all `Entity2`, and
       
   186 when you view `Entity2` you want to list all `Entity3`.
       
   187 
       
   188 In ``entities.py``::
       
   189 
       
   190   class Entity1(TreeMixIn, AnyEntity):
       
   191       id = 'Entity1'
       
   192       __implements__ = AnyEntity.__implements__ + (ITree,)
       
   193       __rtags__ = {('is_related_to', 'Entity2', 'object'): 'link'}
       
   194       tree_attribute = 'is_related_to'
       
   195 
       
   196       def children(self, entities=True):
       
   197           return self.different_type_children(entities)
       
   198 
       
   199   class Entity2(TreeMixIn, AnyEntity):
       
   200       id = 'Entity2'
       
   201       __implements__ = AnyEntity.__implements__ + (ITree,)
       
   202       __rtags__ = {('belongs_to', 'Entity3', 'object'): 'link'}
       
   203       tree_attribute = 'belongs_to'
       
   204 
       
   205       def children(self, entities=True):
       
   206           return self.different_type_children(entities)
       
   207 
       
   208 Once this is done, you can define your common view as follows::
       
   209 
       
   210   class E1E2CommonView(baseviews.PrimaryView):
       
   211       accepts = ('Entity11, 'Entity2')
       
   212       
       
   213       def render_entity_relations(self, entity, siderelations):
       
   214           self.wview('list', entity.children(entities=False))
       
   215 
       
   216 
       
   217 *rtags*
       
   218 -------
       
   219 
       
   220 *rtags* allow to specify certain behaviors of relations relative to a given
       
   221 entity type (see later). They are defined on the entity class by the attribute
       
   222 `rtags` which is a dictionary with as keys the triplets ::
       
   223 
       
   224   <relation type>, <target entity type>, <context position ("subject" ou "object")>
       
   225 
       
   226 and as values a `set` or a tuple of markers defining the properties that
       
   227 apply to this relation.
       
   228 
       
   229 It is possible to simplify this dictionary:
       
   230 
       
   231 * if we want to specifiy a single marker, it is not necessary to
       
   232   use a tuple as value, the marker by itself (character string)
       
   233   is enough
       
   234 * if we only care about a single type of relation and not about the target
       
   235   and the context position (or when this one is not ambigous), we can simply
       
   236   use the name of the relation type as key
       
   237 * if we want a marker to apply independently from the target entity type,
       
   238   we have to use the string `*` as target entity type
       
   239 
       
   240 
       
   241 Please note that this dictionary is *treated at the time the class is created*.
       
   242 It is automatically merged with the parent class(es) (no need to copy the
       
   243 dictionary from the parent class to modify it). Also, modifying it after the 
       
   244 class is created will not have any effect...
       
   245 
       
   246 .. include:: B0031-define-entities.en.txt
       
   247