|
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 |