|
1 .. -*- coding: utf-8 -*- |
|
2 |
|
3 .. _DefinitionVues: |
|
4 |
|
5 Views definition |
|
6 ================ |
|
7 |
|
8 Basic class for views |
|
9 --------------------- |
|
10 |
|
11 Class `View` (`cubicweb.common.view`) |
|
12 ````````````````````````````````````` |
|
13 |
|
14 A view writes in its output exit thanks to its attribute `w` (`UStreamIO`). |
|
15 |
|
16 The basic interface for views is as follows: |
|
17 |
|
18 * `dispatch(**context)`, render the view by calling `call` or |
|
19 `cell_call` depending on the given parameters |
|
20 * `call(**kwargs)`, call the view for a complete result set or null |
|
21 * `cell_call(row, col, **kwargs)`, call the view for a given cell of a result set |
|
22 * `url()`, returns the URL enabling us to get the view with the current |
|
23 result set |
|
24 * `view(__vid, rset, __fallback_vid=None, **kwargs)`, call the view of identifier |
|
25 `__vid` on the given result set. It is possible to give a view identifier |
|
26 of fallback that will be used if the view requested is not applicable to the |
|
27 result set |
|
28 |
|
29 * `wview(__vid, rset, __fallback_vid=None, **kwargs)`, similar to `view` except |
|
30 the flow is automatically passed in the parameters |
|
31 |
|
32 * `html_headers()`, returns a list of HTML headers to set by the main template |
|
33 |
|
34 * `page_title()`, returns the title to use in the HTML header `title` |
|
35 |
|
36 * `creator(eid)`, returns the eid and the login of the entity creator of the entity |
|
37 having the eid given in the parameter |
|
38 |
|
39 Other basic classes: |
|
40 |
|
41 * `EntityView`, view applying to lines or cell containing an entity (e.g. an eid) |
|
42 * `StartupView`, start view that does not require a result set to apply to |
|
43 * `AnyRsetView`, view applied to any result set |
|
44 |
|
45 |
|
46 The selection view principle |
|
47 ---------------------------- |
|
48 |
|
49 A view includes : |
|
50 |
|
51 - an identifier (all objects in `LAX` are entered in a registry |
|
52 and this identifier will be used as a key) |
|
53 |
|
54 - a filter to select the resulsets it can be applied to |
|
55 |
|
56 |
|
57 For a given identifier, multiple views can be defined. `CubicWeb` uses |
|
58 a selector which computes scores so that it can identify and select the |
|
59 best view to apply in context. The selector library is in |
|
60 ``cubicweb.common.selector`` and a library of the methods used to |
|
61 compute scores is in ``cubicweb.vregistry.vreq``. |
|
62 |
|
63 |
|
64 `CubicWeb` provides a lot of standard views, for a complete list, you |
|
65 will have to read the code in directory ``cubicweb/web/views/`` (XXX |
|
66 improve doc). |
|
67 |
|
68 For example, the view named ``primary`` is the one used to display |
|
69 a single entity. |
|
70 |
|
71 If you want to change the way a ``BlogEntry`` is displayed, just |
|
72 override the view ``primary`` in ``BlogDemo/views.py`` :: |
|
73 |
|
74 01. from ginco.web.views import baseviews |
|
75 02. |
|
76 03. class BlogEntryPrimaryView(baseviews.PrimaryView): |
|
77 04. |
|
78 05. accepts = ('BlogEntry',) |
|
79 06. |
|
80 07. def cell_call(self, row, col): |
|
81 08. entity = self.entity(row, col) |
|
82 09. self.w(u'<h1>%s</h1>' % entity.title) |
|
83 10. self.w(u'<p>published on %s in category %s</p>' % \ |
|
84 11. (entity.publish_date.strftime('%Y-%m-%d'), entity.category)) |
|
85 12. self.w(u'<p>%s</p>' % entity.text) |
|
86 |
|
87 The above source code defines a new primary view (`line 03`) for |
|
88 ``BlogEntry`` (`line 05`). |
|
89 |
|
90 Since views are applied to resultsets and resulsets can be tables of |
|
91 data, it is needed to recover the entity from its (row,col) |
|
92 coordinates (`line 08`). We will get to this in more detail later. |
|
93 |
|
94 The view has a ``self.w()`` method that is used to output data. Here `lines |
|
95 09-12` output HTML tags and values of the entity's attributes. |
|
96 |
|
97 When displaying same blog entry as before, you will notice that the |
|
98 page is now looking much nicer. |
|
99 |
|
100 .. image:: images/lax-book.09-new-view-blogentry.en.png |
|
101 :alt: blog entries now look much nicer |
|
102 |
|
103 Let us now improve the primary view of a blog :: |
|
104 |
|
105 01. class BlogPrimaryView(baseviews.PrimaryView): |
|
106 02. |
|
107 03. accepts = ('Blog',) |
|
108 04. |
|
109 05. def cell_call(self, row, col): |
|
110 06. entity = self.entity(row, col) |
|
111 07. self.w(u'<h1>%s</h1>' % entity.title) |
|
112 08. self.w(u'<p>%s</p>' % entity.description) |
|
113 09. rset = self.req.execute('Any E WHERE E entry_of B, B eid "%s"' % entity.eid) |
|
114 10. self.wview('primary', rset) |
|
115 |
|
116 In the above source code, `lines 01-08` are similar to the previous |
|
117 view we defined. |
|
118 |
|
119 At `line 09`, a simple request in made to build a resultset with all |
|
120 the entities linked to the current ``Blog`` entity by the relationship |
|
121 ``entry_of``. The part of the framework handling the request knows |
|
122 about the schema and infer that such entities have to be of the |
|
123 ``BlogEntry`` kind and retrieves them. |
|
124 |
|
125 The request returns a selection of data called a resultset. At |
|
126 `line 10` the view 'primary' is applied to this resultset to output |
|
127 HTML. |
|
128 |
|
129 **This is to be compared to interfaces and protocols in object-oriented |
|
130 languages. Applying a given view to all the entities of a resultset only |
|
131 requires the availability, for each entity of this resultset, of a |
|
132 view with that name that can accepts the entity.** |
|
133 |
|
134 Assuming we added entries to the blog titled `MyLife`, displaying it |
|
135 now allows to read its description and all its entries. |
|
136 |
|
137 .. image:: images/lax-book.10-blog-with-two-entries.en.png |
|
138 :alt: a blog and all its entries |
|
139 |
|
140 **Before we move forward, remember that the selection/view principle is |
|
141 at the core of `CubicWeb`. Everywhere in the engine, data is requested |
|
142 using the RQL language, then HTML/XML/text/PNG is output by applying a |
|
143 view to the resultset returned by the query. That is where most of the |
|
144 flexibility comes from.** |
|
145 |
|
146 [WRITE ME] |
|
147 |
|
148 * implementing interfaces, calendar for blog entries |
|
149 * show that a calendar view can export data to ical |
|
150 |
|
151 We will implement the cubicwweb.interfaces.ICalendarable interfaces on |
|
152 entities.BloEntry and apply the OneMonthCalendar and iCalendar views |
|
153 to resultsets like "Any E WHERE E is BlogEntry" |
|
154 |
|
155 * create view "blogentry table" with title, publish_date, category |
|
156 |
|
157 We will show that by default the view that displays |
|
158 "Any E,D,C WHERE E publish_date D, E category C" is the table view. |
|
159 Of course, the same can be obtained by calling |
|
160 self.wview('table',rset) |
|
161 |
|
162 * in view blog, select blogentries and apply view "blogentry table" |
|
163 * demo ajax by filtering blogentry table on category |
|
164 |
|
165 we did the same with 'primary', but with tables we can turn on filters |
|
166 and show that ajax comes for free. |
|
167 [FILLME] |
|
168 |
|
169 |
|
170 Templates |
|
171 --------- |
|
172 |
|
173 *Templates* are specific view that does not depend on a result set. The basic |
|
174 class `Template` (`cubicweb.common.view`) is derived from the class `View`. |
|
175 |
|
176 To build a HTML page, a *main template* is used. In general, the template of |
|
177 identifier `main` is the one (it is not used in case an error is raised or for |
|
178 the login form for example). This template uses other templates in addition |
|
179 to the views which depends on the content to generate the HTML page to return. |
|
180 |
|
181 A *template* is responsible for: |
|
182 |
|
183 1. executing RQL query of data to render if necessarry |
|
184 2. identifying the view to use to render data if it is not specified |
|
185 3. composing the HTML page to return |
|
186 |
|
187 |
|
188 The default main template (`cubicweb.web.views.basetemplates.TheMainTemplate`) |
|
189 ------------------------------------------------------------------------------ |
|
190 |
|
191 The default main template build the page based on the following pattern: |
|
192 |
|
193 .. image:: images/main_template_layout.png |
|
194 |
|
195 The rectangle containing `view.dispathc()` represents the area where the content |
|
196 view has to be displayed. The others represents sub-templates called to complete |
|
197 the page. A default implementation of those is provided in |
|
198 `cubicweb.views.basetemplates`. You can, of course, overload those sub-templates |
|
199 to implement your own customization of the HTML page. |
|
200 |
|
201 We can also control certain aspects of the main template thanks to the following |
|
202 forms parameters: |
|
203 |
|
204 * `__notemplate`, if present (whatever the value assigned), only the content view |
|
205 is returned |
|
206 * `__force_display`, if present and its value is not null, no navigation |
|
207 whatever the number of entities to display |
|
208 * `__method`, if the result set to render contains only one entity and this |
|
209 parameter is set, it refers to a method to call on the entity by passing it |
|
210 the dictionnary of the forms parameters, before going the classic way (through |
|
211 step 1 and 2 described juste above) |
|
212 |
|
213 .. include:: B031-views-stdlib.en.txt |
|
214 |
|
215 |
|
216 XML views, binaries... |
|
217 ---------------------- |
|
218 For the views generating other formats that HTML (an image generated dynamically |
|
219 for example), and which can not usually be included in the HTML page generated |
|
220 by the main template (see above), you have to: |
|
221 |
|
222 * set the atribute `templatable` of the class to `False` |
|
223 * set, through the attribute `content_type` of the class, the MIME type generated |
|
224 by the view to `application/octet-stream` |
|
225 |
|
226 For the views dedicated to binary content creation (an image dynamically generated |
|
227 for example), we have to set the attribute `binary` of the class to `True` (which |
|
228 implies that `templateable == False`, so that the attribute `w` of the view could be |
|
229 replaced by a binary flow instead of unicode). |
|
230 |
|
231 (X)HTML tricks to apply |
|
232 ----------------------- |
|
233 |
|
234 Some web browser (Firefox for example) are not happy with empty `<div>` |
|
235 (by empty we mean that there is no content in the tag, but there |
|
236 could be attributes), so we should always use `<div></div>` even if |
|
237 it is empty and not use `<div/>`. |
|
238 |