10 Using and combining existant selectors |
10 Using and combining existant selectors |
11 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
11 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
12 |
12 |
13 You can combine selectors using the `&`, `|` and `~` operators. |
13 You can combine selectors using the `&`, `|` and `~` operators. |
14 |
14 |
15 When two selectors are combined using the `&` operator (formerly `chainall`), it |
15 When two selectors are combined using the `&` operator, it means that |
16 means that both should return a positive score. On success, the sum of scores is returned. |
16 both should return a positive score. On success, the sum of scores is |
17 |
17 returned. |
18 When two selectors are combined using the `|` operator (former `chainfirst`), it |
18 |
19 means that one of them should return a positive score. On success, the first |
19 When two selectors are combined using the `|` operator, it means that |
|
20 one of them should return a positive score. On success, the first |
20 positive score is returned. |
21 positive score is returned. |
21 |
22 |
22 You can also "negate" a selector by precedeing it by the `~` unary operator. |
23 You can also "negate" a selector by precedeing it by the `~` unary operator. |
23 |
24 |
24 Of course you can use parens to balance expressions. |
25 Of course you can use parenthesis to balance expressions. |
25 |
|
26 .. Note: |
|
27 When one chains selectors, the final score is the sum of the score of each |
|
28 individual selector (unless one of them returns 0, in which case the object is |
|
29 non selectable) |
|
30 |
|
31 |
26 |
32 Example |
27 Example |
33 ~~~~~~~ |
28 ~~~~~~~ |
34 |
29 |
35 The goal: when on a Blog, one wants the RSS link to refer to blog entries, not to |
30 The goal: when on a blog, one wants the RSS link to refer to blog entries, not to |
36 the blog entity itself. |
31 the blog entity itself. |
37 |
32 |
38 To do that, one defines a method on entity classes that returns the RSS stream |
33 To do that, one defines a method on entity classes that returns the |
39 url for a given entity. The default implementation on |
34 RSS stream url for a given entity. The default implementation on |
40 :class:`~cubicweb.entities.AnyEntity` (the generic entity class used as base for |
35 :class:`~cubicweb.entities.AnyEntity` (the generic entity class used |
41 all others) and a specific implementation on Blog will do what we want. |
36 as base for all others) and a specific implementation on `Blog` will |
42 |
37 do what we want. |
43 But when we have a result set containing several Blog entities (or different |
38 |
44 entities), we don't know on which entity to call the aforementioned method. In |
39 But when we have a result set containing several `Blog` entities (or |
45 this case, we keep the generic behaviour. |
40 different entities), we don't know on which entity to call the |
|
41 aforementioned method. In this case, we keep the generic behaviour. |
46 |
42 |
47 Hence we have two cases here, one for a single-entity rsets, the other for |
43 Hence we have two cases here, one for a single-entity rsets, the other for |
48 multi-entities rsets. |
44 multi-entities rsets. |
49 |
45 |
50 In web/views/boxes.py lies the RSSIconBox class. Look at its selector: |
46 In web/views/boxes.py lies the RSSIconBox class. Look at its selector: |
51 |
47 |
52 .. sourcecode:: python |
48 .. sourcecode:: python |
53 |
49 |
54 class RSSIconBox(ExtResourcesBoxTemplate): |
50 class RSSIconBox(ExtResourcesBoxTemplate): |
55 '''just display the RSS icon on uniform result set''' |
51 ''' just display the RSS icon on uniform result set ''' |
56 __select__ = ExtResourcesBoxTemplate.__select__ & non_final_entity() |
52 __select__ = ExtResourcesBoxTemplate.__select__ & non_final_entity() |
57 |
53 |
58 It takes into account: |
54 It takes into account: |
59 |
55 |
60 * the inherited selection criteria (one has to look them up in the class |
56 * the inherited selection criteria (one has to look them up in the class |
114 # display a link to the connected user object with a loggout link |
110 # display a link to the connected user object with a loggout link |
115 ... |
111 ... |
116 |
112 |
117 The proper way to implement this with |cubicweb| is two have two different |
113 The proper way to implement this with |cubicweb| is two have two different |
118 classes sharing the same identifier but with different selectors so you'll get |
114 classes sharing the same identifier but with different selectors so you'll get |
119 the correct one according to the context: |
115 the correct one according to the context. |
120 |
116 |
|
117 .. sourcecode:: python |
121 |
118 |
122 class UserLink(component.Component): |
119 class UserLink(component.Component): |
123 '''display a link to the connected user object with a loggout link''' |
120 '''display a link to the connected user object with a loggout link''' |
124 __regid__ = 'loggeduserlink' |
121 __regid__ = 'loggeduserlink' |
125 __select__ = component.Component.__select__ & authenticated_user() |
122 __select__ = component.Component.__select__ & authenticated_user() |
135 |
132 |
136 def call(self): |
133 def call(self): |
137 # display login link |
134 # display login link |
138 ... |
135 ... |
139 |
136 |
140 The big advantage, aside readibily once you're familiar with the system, is that |
137 The big advantage, aside readability once you're familiar with the |
141 your cube becomes much more easily customizable by improving componentization. |
138 system, is that your cube becomes much more easily customizable by |
|
139 improving componentization. |
142 |
140 |
143 |
141 |
144 .. _CustomSelectors: |
142 .. _CustomSelectors: |
145 |
143 |
146 Defining your own selectors |
144 Defining your own selectors |
147 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
145 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
148 |
146 |
149 .. autodocstring:: cubicweb.appobject::objectify_selector |
147 .. autodocstring:: cubicweb.appobject::objectify_selector |
150 |
148 |
151 In other case, you can take a look at the following abstract base classes: |
149 In other cases, you can take a look at the following abstract base classes: |
152 |
150 |
153 .. autoclass:: cubicweb.selectors.ExpectedValueSelector |
151 .. autoclass:: cubicweb.selectors.ExpectedValueSelector |
154 .. autoclass:: cubicweb.selectors.EClassSelector |
152 .. autoclass:: cubicweb.selectors.EClassSelector |
155 .. autoclass:: cubicweb.selectors.EntitySelector |
153 .. autoclass:: cubicweb.selectors.EntitySelector |
156 |
154 |
252 You can also give to :class:`traced_selection` the identifiers of objects on |
250 You can also give to :class:`traced_selection` the identifiers of objects on |
253 which you want to debug selection ('oid1' and 'oid2' in the example above). |
251 which you want to debug selection ('oid1' and 'oid2' in the example above). |
254 |
252 |
255 .. sourcecode:: python |
253 .. sourcecode:: python |
256 |
254 |
257 >>> with traced_selection( ('oid1', 'oid2') ): |
255 >>> with traced_selection( ('regid1', 'regid2') ): |
258 ... # some code in which you want to debug selectors |
256 ... # some code in which you want to debug selectors |
259 ... # for objects with id 'oid1' and 'oid2' |
257 ... # for objects with __regid__ 'regid1' and 'regid2' |
260 |
258 |
261 """ |
259 A potentially usefull point to set up such a tracing function is |
|
260 the `cubicweb.vregistry.Registry.select` method body. |
|
261 """ |
|
262 |
262 def __init__(self, traced='all'): |
263 def __init__(self, traced='all'): |
263 self.traced = traced |
264 self.traced = traced |
264 |
265 |
265 def __enter__(self): |
266 def __enter__(self): |
266 global TRACED_OIDS |
267 global TRACED_OIDS |