|
1 .. -*- coding: utf-8 -*- |
|
2 |
|
3 .. _DefinitionVues: |
|
4 |
|
5 Définition de vues |
|
6 ================== |
|
7 |
|
8 Les classes de base des vues |
|
9 ---------------------------- |
|
10 |
|
11 La class `View` (`cubicweb.common.view`) |
|
12 ```````````````````````````````````````` |
|
13 Un vue écrit dans son flux de sortie via son attribut `w` (`UStreamIO`). |
|
14 |
|
15 L'interface de base des vues est la suivante : |
|
16 |
|
17 * `dispatch(**context)`, appelle ("rend") la vue en appellent `call` ou |
|
18 `cell_call` en fonction des arguments passé |
|
19 * `call(**kwargs)`, appelle la vue pour un result set complet ou nul |
|
20 * `cell_call(row, col, **kwargs)`, appelle la vue pour une cellule donnée d'un |
|
21 result set |
|
22 * `url()`, retourne l'url permettant d'obtenir cette vue avec le result set en |
|
23 cours |
|
24 * `view(__vid, rset, __fallback_vid=None, **kwargs)`, appelle la vue |
|
25 d'identificant `__vid` sur le result set donné. Il est possible de données un |
|
26 identificant de vue de "fallback" qui sera utilisé si la vue demandée n'est |
|
27 pas applicable au result set |
|
28 |
|
29 * `wview(__vid, rset, __fallback_vid=None, **kwargs)`, pareil que `view` mais |
|
30 passe automatiquement le flux en argument |
|
31 |
|
32 * `html_headers()`, retourne une liste d'en-tête HTML à placer par le template |
|
33 principal |
|
34 |
|
35 * `page_title()`, retourne le titre à utiliser dans l'en tête HTML `title` |
|
36 |
|
37 * `creator(eid)`, retourne l'eid et le login du créateur de l'entité ayant |
|
38 l'eid passé en argument |
|
39 |
|
40 Autres classes de base : |
|
41 |
|
42 * `EntityView`, vue s'appliquant à aux lignes ou cellule contenant une entité |
|
43 (eg un eid) |
|
44 * `StartupView`, vue de départ n'ayant pas besoin de result set |
|
45 * `AnyRsetView`, vue s'appliquant à n'importe quelle result set |
|
46 |
|
47 Le mecanisme de selection de vues |
|
48 --------------------------------- |
|
49 |
|
50 Pour un identifiant de vue donne, plusieurs vues peuvent etre definies. |
|
51 `CubicWeb` utilise un selecteur qui permet de calculer un score et d'identifier |
|
52 la vue la plus appropriee a appliquer dans le contexte. La librairie du selecteur |
|
53 se trouve dans ``cubicweb.common.selector`` et une librairie des methodes utilisees |
|
54 pour calculer les scores est dans ``cubicweb.vregistry.vreq``. |
|
55 |
|
56 [FROM-LAX-BOOK] |
|
57 |
|
58 Tip: when modifying views, you do not need to restart the local |
|
59 server. Just save the file in your editor and reload the page in your |
|
60 browser to see the changes. |
|
61 |
|
62 With `LAX`, views are defined by Python classes. A view includes : |
|
63 |
|
64 - an identifier (all objects in `LAX` are entered in a registry |
|
65 and this identifier will be used as a key) |
|
66 |
|
67 - a filter to select the resulsets it can be applied to |
|
68 |
|
69 `LAX` provides a lot of standard views, for a complete list, you |
|
70 will have to read the code in directory ``ginco/web/views/`` (XXX |
|
71 improve doc). |
|
72 |
|
73 For example, the view named ``primary`` is the one used to display |
|
74 a single entity. |
|
75 |
|
76 If you want to change the way a ``BlogEntry`` is displayed, just |
|
77 override the view ``primary`` in ``BlogDemo/views.py`` :: |
|
78 |
|
79 01. from ginco.web.views import baseviews |
|
80 02. |
|
81 03. class BlogEntryPrimaryView(baseviews.PrimaryView): |
|
82 04. |
|
83 05. accepts = ('BlogEntry',) |
|
84 06. |
|
85 07. def cell_call(self, row, col): |
|
86 08. entity = self.entity(row, col) |
|
87 09. self.w(u'<h1>%s</h1>' % entity.title) |
|
88 10. self.w(u'<p>published on %s in category %s</p>' % \ |
|
89 11. (entity.publish_date.strftime('%Y-%m-%d'), entity.category)) |
|
90 12. self.w(u'<p>%s</p>' % entity.text) |
|
91 |
|
92 The above source code defines a new primary view (`line 03`) for |
|
93 ``BlogEntry`` (`line 05`). |
|
94 |
|
95 Since views are applied to resultsets and resulsets can be tables of |
|
96 data, it is needed to recover the entity from its (row,col) |
|
97 coordinates (`line 08`). We will get to this in more detail later. |
|
98 |
|
99 The view has a ``self.w()`` method that is used to output data. Here `lines |
|
100 09-12` output HTML tags and values of the entity's attributes. |
|
101 |
|
102 When displaying same blog entry as before, you will notice that the |
|
103 page is now looking much nicer. |
|
104 |
|
105 .. image:: images/lax-book.09-new-view-blogentry.fr.png |
|
106 :alt: blog entries now look much nicer |
|
107 |
|
108 Let us now improve the primary view of a blog :: |
|
109 |
|
110 01. class BlogPrimaryView(baseviews.PrimaryView): |
|
111 02. |
|
112 03. accepts = ('Blog',) |
|
113 04. |
|
114 05. def cell_call(self, row, col): |
|
115 06. entity = self.entity(row, col) |
|
116 07. self.w(u'<h1>%s</h1>' % entity.title) |
|
117 08. self.w(u'<p>%s</p>' % entity.description) |
|
118 09. rset = self.req.execute('Any E WHERE E entry_of B, B eid "%s"' % entity.eid) |
|
119 10. self.wview('primary', rset) |
|
120 |
|
121 In the above source code, `lines 01-08` are similar to the previous |
|
122 view we defined. |
|
123 |
|
124 At `line 09`, a simple request in made to build a resultset with all |
|
125 the entities linked to the current ``Blog`` entity by the relationship |
|
126 ``entry_of``. The part of the framework handling the request knows |
|
127 about the schema and infer that such entities have to be of the |
|
128 ``BlogEntry`` kind and retrieves them. |
|
129 |
|
130 The request returns a selection of data called a resultset. At |
|
131 `line 10` the view 'primary' is applied to this resultset to output |
|
132 HTML. |
|
133 |
|
134 **This is to be compared to interfaces and protocols in object-oriented |
|
135 languages. Applying a given view to all the entities of a resultset only |
|
136 requires the availability, for each entity of this resultset, of a |
|
137 view with that name that can accepts the entity.** |
|
138 |
|
139 Assuming we added entries to the blog titled `MyLife`, displaying it |
|
140 now allows to read its description and all its entries. |
|
141 |
|
142 .. image:: images/lax-book.10-blog-with-two-entries.fr.png |
|
143 :alt: a blog and all its entries |
|
144 |
|
145 **Before we move forward, remember that the selection/view principle is |
|
146 at the core of `LAX`. Everywhere in the engine, data is requested |
|
147 using the RQL language, then HTML/XML/text/PNG is output by applying a |
|
148 view to the resultset returned by the query. That is where most of the |
|
149 flexibility comes from.** |
|
150 |
|
151 [WRITE ME] |
|
152 |
|
153 * implementing interfaces, calendar for blog entries |
|
154 * show that a calendar view can export data to ical |
|
155 |
|
156 We will implement the ginco.interfaces.ICalendarable interfaces on |
|
157 entities.BloEntry and apply the OneMonthCalendar and iCalendar views |
|
158 to resultsets like "Any E WHERE E is BlogEntry" |
|
159 |
|
160 * create view "blogentry table" with title, publish_date, category |
|
161 |
|
162 We will show that by default the view that displays |
|
163 "Any E,D,C WHERE E publish_date D, E category C" is the table view. |
|
164 Of course, the same can be obtained by calling |
|
165 self.wview('table',rset) |
|
166 |
|
167 * in view blog, select blogentries and apply view "blogentry table" |
|
168 * demo ajax by filtering blogentry table on category |
|
169 |
|
170 we did the same with 'primary', but with tables we can turn on filters |
|
171 and show that ajax comes for free. |
|
172 [FILLME] |
|
173 |
|
174 Les templates ou patron |
|
175 ----------------------- |
|
176 |
|
177 Les patrons (ou *template*) sont des cas particulier de vue ne dépendant a |
|
178 priori pas d'un result set. La classe de base `Template` (`cubicweb.common.view`) |
|
179 est une classe dérivée de la classe `View`. |
|
180 |
|
181 Pour construire une page HTML, un *template principal* est utilisé. Généralement |
|
182 celui possédant l'identifiant 'main' est utilisé (ce n'est pas le cas lors |
|
183 d'erreur dans celui-ci ou pour le formulaire de login par exemple). Ce patron |
|
184 utilise d'autres patrons en plus des vues dépendants du contenu pour générer la |
|
185 page à renvoyer. |
|
186 |
|
187 C'est ce template qui est chargé : |
|
188 |
|
189 1. d'éxécuter la requête RQL des données à afficher le cas échéant |
|
190 2. éventuellement de déterminer la vue à utiliser pour l'afficher si non |
|
191 spécifiée |
|
192 3. de composer la page à retourner |
|
193 |
|
194 |
|
195 Le patron principal par défaut (`cubicweb.web.views.basetemplates.TheMainTemplate`) |
|
196 ----------------------------------------------------------------------------------- |
|
197 |
|
198 Le template principal par défaut construit la page selon la décomposition |
|
199 suivante : |
|
200 |
|
201 .. image:: images/main_template_layout.png |
|
202 |
|
203 Le rectancle contenant le `view.dispatch()` représente l'emplacement où est |
|
204 inséré la vue de contenu à afficher. Les autres représentent des sous-templates |
|
205 appelé pour construire la page. Les implémentations par défaut de tout ces |
|
206 templates sont dans le module `cubicweb.web.views.basetemplates`. Vous pouvez |
|
207 évidemment surcharger l'un des sous-templates pour modifier l'aspect visuel |
|
208 d'une partie désirée de la page. |
|
209 |
|
210 On peut également contrôler certains comportements du template principal à |
|
211 l'aide des paramètres de formulaire suivante : |
|
212 |
|
213 * `__notemplate`, si présente (quelque soit la valeur associée), seule la vue de |
|
214 contenu est renvoyée |
|
215 * `__force_display`, si présente et contient une valeur non nulle, pas de |
|
216 navigation quelque soit le nombre d'entités à afficher |
|
217 * `__method`, si le result set à afficher ne contient qu'une entité et que ce |
|
218 paramètre est spécifié, celui-ci désigne une méthode à appeler sur l'entité |
|
219 en lui donnant en argument le dictionnaire des paramètres de formulaire, avant |
|
220 de reprendre le comportement classique (s'insère entre les étapes 1. et |
|
221 2. décrites ci-dessus) |
|
222 |
|
223 |
|
224 .. include:: 05-01-views-stdlib.fr.txt |
|
225 |
|
226 |
|
227 Vues xml, binaires... |
|
228 --------------------- |
|
229 Pour les vues générants autre que du html (une image générée dynamiquement par |
|
230 exemple), et qui ne peuvent donc généralement pas être incluse dans la page |
|
231 HTML générée par le template principal (voir ci-dessus), il faut : |
|
232 |
|
233 * placer l'attribut `templatable` de la classe à `False` |
|
234 * indiquer via l'attribut `content_type` de la classe le type MIME généré par la |
|
235 vue 'application/octet-stream' |
|
236 |
|
237 Pour les vues générants un contenu binaire (une image générée dynamiquement par |
|
238 exemple), il faut également placer l'attribut `binary` de la classe à `True` (ce |
|
239 qui implique `templatable == False` afin que l'attribut `w` de la vue soit |
|
240 remplacé par un flux binaire plutôt que unicode. |
|
241 |
|
242 |
|
243 Quelques trucs (X)HTML à respecter |
|
244 ---------------------------------- |
|
245 Certains navigateurs (dont firefox) n'aime pas les `<div>` vides (par vide |
|
246 j'entend sans contenu dans la balise, il peut y avoir des attributs), faut |
|
247 toujours mettre `<div></div>` même s'il n'y a rien dedans, et non `<div/>`. |