doc/book/en/B0031-define-entities.en.txt
author Emile Anclin <emile.anclin@logilab.fr>
Wed, 01 Apr 2009 19:40:51 +0200
changeset 1207 33d0e08a931a
parent 622 2d30c5e1a7d2
child 1353 fb5f014b861d
permissions -rw-r--r--
[doc] trying to get it a little bit more readable

.. -*- coding: utf-8 -*-

Parametrization and specific extensions
---------------------------------------

Dynamic default values
``````````````````````
It is possible to define *static* default values in the schema.
It is also possible to define *dynamic* default values
by defining in the entity class a method `default_<attribut name>` for
a given attribute.


Loaded attributes and default sorting management
````````````````````````````````````````````````

* The class attribute `fetch_attrs` allows to defined in an entity class
  a list of names of attributes or relations that should be automatically
  loaded when we recover the entities of this type. In the case of relations,
  we are limited to *subject of cardinality `?` or `1`* relations.

* The class method `fetch_order(attr, var)` expects an attribute (or relation)
  name as a parameter and a variable name, and it should return a string
  to use in the requirement `ORDER BY` of an RQL query to automatically
  sort the list of entities of such type according to this attribute, or
  `None` if we do not want to sort on the attribute given in the parameter.
  By default, the entities are sorted according to their creation date.

* The class method `fetch_unrelated_order(attr, var)` is similar to the 
  method `fetch_order` except that it is essentially used to control
  the sorting of drop-down lists enabling relations creation in 
  the editing view of an entity.

The function `fetch_config(fetchattrs, mainattr=None)` simplifies the
definition of the attributes to load and the sorting by returning a 
list of attributes to pre-load (considering automatically the attributes
of `AnyEntity`) and a sorting function based on the main attribute
(the second parameter if specified otherwisethe first attribute from
the list `fetchattrs`).
This function is defined in `cubicweb.entities`.

For example: ::

  class Transition(AnyEntity):
    """..."""
    id = 'Transition'
    fetch_attrs, fetch_order = fetch_config(['name'])

Indicates that for the entity type "Transition", you have to pre-load
the attribute `name` and sort by default on this attribute.


Editing forms management
````````````````````````
It is possible to manage attributes/relations in the simple or multiple
editing form thanks to the following *rtags*: 

* `primary`, indicates that an attribute or a relation has to be
  inserted **in the simple or multiple editing forms**. In the case of
  a relation, the related entity editing form will be included in the
  editing form and represented as a combobox. Each item of the
  combobox is a link to an existing entity.

* `secondary`, indicates that an attribute or a relation has to be
  inserted **in the simple editing form only**. In the case of a
  relation, the related entity editing form will be included in the
  editing form and represented as a combobox. Each item of the combobox
  is a link to an existing entity.

* `inlineview`, includes the target entity's form in the editing form
  of the current entity. It allows to create the target entity in the
  same time as the current entity.

* `generic`, indicates that a relation has to be inserted in the simple
  editing form, in the generic box of relation creation.

* `generated`, indicates that an attribute is dynamically computed
  or other,  and that it should not be displayed in the editing form.

If necessary, it is possible to overwrite the method  
`relation_category(rtype, x='subject')` to dynamically compute
a relation editing category.

``add_related`` box management
``````````````````````````````

The box ``add_related`` is an automatic box that allows to create
an entity automatically related to the initial entity (context in
which the box is displayed). By default, the links generated in this
box are computed from the schema properties of the displayed entity,
but it is possible to explicitely specify them thanks to the
following *rtags*:

* `link`, indicates that a relation is in general created pointing
  to an existing entity and that we should not to display a link
  for this relation

* `create`, indicates that a relation is in general created pointing
  to new entities and that we should display a link to create a new
  entity and link to it automatically


If necessary, it is possible to overwrite the method  
`relation_mode(rtype, targettype, x='subject')` to dynamically
compute a relation creation category.

Please note that if at least one action belongs to the `addrelated` category,
the automatic behavior is desactivated in favor of an explicit behavior
(e.g. display of `addrelated` category actions only).


Filtering table forms management
````````````````````````````````

By default, the view ``table`` manages automatically a filtering
form of its content. The algorithm is as follows:

1. we consider that the first column contains the entities to constraint
2. we collect the first entity of the table (row 0) to represent all the 
   others
3. for all the other variables defined in the original request:
   
   1. if the variable is related to the main variable by at least one relation
   2. we call the method ``filterform_vocabulary(rtype, x)`` on the entity,
      if nothing is returned (meaning a tuple `Non`, see below), we go to the
      next variable, otherwise a form filtering element is created based on
      the vocabulary values returned

4. there are no other limitations to the `RQL`, it can include sorting, grouping
   conditions... JavaScript functions are used to regenerate a request based on the
   initial request and on the selected values from the filtering form.

The method ``filterform_vocabulary(rtype, x, var, rqlst, args, cachekey)`` takes 
the name of a relation and the target as parameters,
[XXX what does it mean ?]
 which indicates of the
entity on which we apply the method is subject or object of the relation. It
has to return:

* a 2-uple of None if it does not know how to handle the relation

* a type and a list containing the vocabulary
  
  * the list has to contain couples (value, label)
  * the type indicates if the value designate an integer (`type == 'int'`),
    a string (`type =='string'` or a non-final relation (`type == 'eid'`)

For example in our application managing tickets, we want to be able to filter
them by :

* type
* priority
* state (in_state)
* tag (tags)
* version (done_in)

For that we define the following method: ::


    class Ticket(AnyEntity):

	    ...

    	def filterform_vocabulary(self, rtype, x, var, rqlst, args, cachekey):
	        _ = self.req._
	        if rtype == 'type':
        		return 'string', [(x, _(x)) for x in ('bug', 'story')]
	        if rtype == 'priority':
    	    	return 'string', [(x, _(x)) for x in ('minor', 'normal', 'important')]
    	    if rtype == 'done_in':
	        	rql = insert_attr_select_relation(rqlst, var, rtype, 'num')
		        return 'eid', self.req.execute(rql, args, cachekey)
	        return super(Ticket, self).filterform_vocabulary(rtype, x, var, rqlst,
							     args, cachekey)

.. note::
  Filtering on state and tags is automatically installed, no need to handle it.