doc/book/en/devweb/facets.rst
branchstable
changeset 5394 105011657405
parent 5286 43d7044f8d0b
child 6120 c000e41316ec
equal deleted inserted replaced
5393:875bdc0fe8ce 5394:105011657405
       
     1 The facets system
       
     2 -----------------
       
     3 
       
     4 Facets allow to restrict searches according to some criteria. CubicWeb
       
     5 has a builtin `facet`_ system to define restrictions `filters`_ really
       
     6 as easily as possible. A few base classes for facets are provided in
       
     7 ``cubicweb.web.facet.py``. All classes inherits from the base class
       
     8 ``AbstractFacet``.
       
     9 
       
    10 Here is an overview of the facets rendering pick from the `tracker` cube:
       
    11 
       
    12 .. image:: ../images/facet_overview.png
       
    13 
       
    14 Facets will appear on each page presenting more than one entity.
       
    15 
       
    16 
       
    17 
       
    18 VocabularyFacet
       
    19 ~~~~~~~~~~~~~~~~
       
    20 The ``VocabularyFacet`` inherits from the ``AbstractFacet``.
       
    21 A class which inherits from VocabularyFacets must redefine these methods:
       
    22 
       
    23 .. automethod:: cubicweb.web.facet.VocabularyFacet.vocabulary
       
    24 .. automethod:: cubicweb.web.facet.VocabularyFacet.possible_values
       
    25 
       
    26 RelationFacet
       
    27 ~~~~~~~~~~~~~~
       
    28 
       
    29 The ``RelationFacet`` inherits from the ``VocabularyFacet``. It allows to filter entities according to certain relation's values. Generally, you just have to define some class attributes like:
       
    30 
       
    31 - rtype: the name of the relation
       
    32 - role: the default value is set to `subject`
       
    33 - target_attr: needed if it is not the default attribute of the entity
       
    34 
       
    35 
       
    36 To illustrate this facet, let's take for example an *excerpt* of the schema of an office location search application:
       
    37 
       
    38 .. sourcecode:: python
       
    39 
       
    40   class Office(WorkflowableEntityType):
       
    41       price = Int(description='euros / m2 / HC / HT')
       
    42       surface = Int(description='m2')
       
    43       description = RichString(fulltextindexed=True)
       
    44       has_address = SubjectRelation('PostalAddress',
       
    45                                     cardinality='1?',
       
    46                                     composite='subject')
       
    47       proposed_by = SubjectRelation('Agency')
       
    48       comments = ObjectRelation('Comment',
       
    49                                 cardinality='1*',
       
    50                                 composite='object')
       
    51       screenshots = SubjectRelation(('File', 'Image'),
       
    52                                     cardinality='*1',
       
    53                                     composite='subject')
       
    54 
       
    55 
       
    56 We define a facet to filter offices according to the attribute
       
    57 `postalcode` of their associated `PostalAdress`.
       
    58 
       
    59 .. sourcecode:: python
       
    60 
       
    61   class PostalCodeFacet(RelationFacet):
       
    62       __regid__ = 'postalcode-facet'      # every registered class must have an id
       
    63       __select__ = implements('Office')   # this facet should only be selected when
       
    64                                           # visualizing offices
       
    65       rtype = 'has_address'               # this facet is a filter on the entity linked to
       
    66                                           # the office thrhough the relation
       
    67                                           # has_address
       
    68       target_attr = 'postalcode'          # the filter's key is the attribute "postal_code"
       
    69                                           # of the target PostalAddress entity
       
    70 
       
    71 
       
    72 AttributeFacet
       
    73 ~~~~~~~~~~~~~~
       
    74 
       
    75 The ``AttributeFacet`` inherits from the ``RelationFacet``. It allows to filter entities according to certain attribute's values.
       
    76 
       
    77 The example below resumes the former schema. We define now a filter based on the `surface` attribute of the
       
    78 `Office`.
       
    79 
       
    80 .. sourcecode:: python
       
    81 
       
    82   class SurfaceFacet(AttributeFacet):
       
    83       __regid__ = 'surface-facet'       # every registered class must have an id
       
    84       __select__ = implements('Office') # this facet should only be selected when
       
    85                                         # visualizing offices
       
    86       rtype = 'surface'                 # the filter's key is the attribute "surface"
       
    87       comparator = '>='                 # override the default value of operator since
       
    88                                         # we want to filter according to a
       
    89                                         # minimal
       
    90                                         # value, not an exact one
       
    91 
       
    92       def rset_vocabulary(self, ___):
       
    93           """override the default vocabulary method since we want to hard-code
       
    94           our threshold values.
       
    95           Not overriding would generate a filter box with all existing surfaces
       
    96           defined in the database.
       
    97           """
       
    98           return [('> 200', '200'), ('> 250', '250'),
       
    99                   ('> 275', '275'), ('> 300', '300')]
       
   100 
       
   101 RangeFacet
       
   102 ~~~~~~~~~~
       
   103 The ``RangeFacet`` inherits from the ``AttributeFacet``. It allows to filter entities according to certain attributes of numerical type.
       
   104 
       
   105 The ``RangeFacet`` displays a slider using `jquery`_ to choose a lower bound and an upper bound.
       
   106 
       
   107 The example below defines a facet to filter a selection of books according to their number of pages.
       
   108 
       
   109 .. sourcecode:: python
       
   110 
       
   111    class BookPagesFacet(RangeFacet):
       
   112        __regid__ = 'priority-facet'
       
   113        __select__ = RangeFacet.__select__ & implements('Book')
       
   114        rtype = 'pages'
       
   115 
       
   116 The image below display the rendering of the ``RangeFacet``:
       
   117 
       
   118 .. image:: ../images/facet_range.png
       
   119 
       
   120 DateRangeFacet
       
   121 ~~~~~~~~~~~~~~
       
   122 The ``DateRangeFacet`` inherits from the ``RangeFacet``. It allows to filter entities according to certain attributes of date type.
       
   123 
       
   124 Here is an example of code that defines a facet to filter
       
   125 musical works according to their composition date:
       
   126 
       
   127 .. sourcecode:: python
       
   128 
       
   129     class CompositionDateFacet(DateRangeFacet):
       
   130         # 1. make sure this facet is displayed only on Track selection
       
   131         __select__ = DateRangeFacet.__select__ & implements('Track')
       
   132         # 2. give the facet an id required by CubicWeb)
       
   133         __regid__ = 'compdate-facet'
       
   134         # 3. specify the attribute name that actually stores the date in the DB
       
   135         rtype = 'composition_date'
       
   136 
       
   137 With this facet, on each page displaying tracks, you'll be able to filter them
       
   138 according to their composition date with a jquery slider.
       
   139 
       
   140 The image below display the rendering of the ``DateRangeFacet``:
       
   141 
       
   142 .. image:: ../images/facet_date_range.png
       
   143 
       
   144 
       
   145 HasRelationFacet
       
   146 ~~~~~~~~~~~~~~~~
       
   147 
       
   148 The ``DateRangeFacet`` inherits from the ``AbstractFacet``. It will
       
   149 display a simple checkbox and lets you refine your selection in order
       
   150 to get only entities that actually use this relation.
       
   151 
       
   152 Here is an example of the rendering of the ``HasRelationFacet`` to
       
   153 filter entities with image and the corresponding code:
       
   154 
       
   155 .. image:: ../images/facet_has_image.png
       
   156 
       
   157 .. sourcecode:: python
       
   158 
       
   159   class HasImageFacet(HasRelationFacet):
       
   160       __regid__ = 'hasimage-facet'
       
   161       __select__ = HasRelationFacet.__select__ & implements('Book')
       
   162       rtype = 'has_image'
       
   163 
       
   164 
       
   165 
       
   166 To use ``HasRelationFacet`` on a reverse relation add ``role = 'object'`` in
       
   167 it's definitions.
       
   168 
       
   169 .. _facet: http://en.wikipedia.org/wiki/Faceted_browser
       
   170 .. _filters: http://www.cubicweb.org/blogentry/154152
       
   171 .. _jquery: http://www.jqueryui.com/
       
   172