1 .. -*- coding: utf-8 -*- |
|
2 |
|
3 .. _Steps: |
|
4 |
|
5 Steps for creating your cube |
|
6 ---------------------------- |
|
7 |
|
8 The following steps will help you to create and customize a new cube. |
|
9 |
|
10 1. :ref:`CreateYourCube` |
|
11 |
|
12 Create the directory to hold the code of your cube. The most important |
|
13 files that will be useful to customize your newly created cube are: |
|
14 |
|
15 * schema.py: contains the data model |
|
16 * views.py: contains your custom views |
|
17 * entities.py: contains XXX |
|
18 |
|
19 The detailed structure of the code directory is described in :ref:`cubelayout`. |
|
20 |
|
21 2. :ref:`DefineDataModel` |
|
22 |
|
23 Define the data model of your application. |
|
24 |
|
25 3. :ref:`ExploreYourInstance` |
|
26 |
|
27 Create, run, and explore an instance of your cube. |
|
28 |
|
29 4. :ref:`DefineViews` |
|
30 |
|
31 Customize the views of your data: how and which part of your data are showed. |
|
32 |
|
33 .. note:: views do not define the look'n'feel and the design of your application. For that, you will use CSS and the files located 'blog/data/'. |
|
34 |
|
35 |
|
36 5. :ref:`DefineEntities` |
|
37 |
|
38 Define your own entities to add useful functions when you manipulate your data, especially when you write view. |
|
39 |
|
40 |
|
41 .. _CreateYourCube: |
|
42 |
|
43 Create your cube |
|
44 ---------------- |
|
45 |
|
46 The packages ``cubicweb`` and ``cubicweb-dev`` install a command line |
|
47 tool for *CubicWeb* called ``cubicweb-ctl``. This tool provides a wide |
|
48 range of commands described in details in :ref:`cubicweb-ctl`. |
|
49 |
|
50 Once your *CubicWeb* development environment is set up, you can create |
|
51 a new cube:: |
|
52 |
|
53 cubicweb-ctl newcube blog |
|
54 |
|
55 This will create in the cubes directory (``/path/to/forest/cubes`` for Mercurial |
|
56 installation, ``/usr/share/cubicweb/cubes`` for debian packages installation) |
|
57 a directory named ``blog`` reflecting the structure described in :ref:`Concepts`. |
|
58 |
|
59 |
|
60 For packages installation, you can still create new cubes in your home directory using the following configuration. Let's say you want to develop your new cubes in `~src/cubes`, then set the following environment variables: |
|
61 :: |
|
62 |
|
63 CW_CUBES_PATH=~/src/cubes |
|
64 CW_MODE=user |
|
65 |
|
66 and then create your new cube using: |
|
67 :: |
|
68 |
|
69 cubicweb-ctl newcube --directory=~/src/cubes blog |
|
70 |
|
71 |
|
72 .. _DefineDataModel: |
|
73 |
|
74 Define your data model |
|
75 ---------------------- |
|
76 |
|
77 The data model or schema is the core of your *CubicWeb* application. |
|
78 It defines the type of content your application will handle. |
|
79 |
|
80 The data model of your cube ``blog`` is defined in the file ``schema.py``: |
|
81 |
|
82 .. sourcecode:: python |
|
83 |
|
84 from yams.buildobjs import EntityType, String, SubjectRelation, Date |
|
85 |
|
86 class Blog(EntityType): |
|
87 title = String(maxsize=50, required=True) |
|
88 description = String() |
|
89 |
|
90 class BlogEntry(EntityType): |
|
91 title = String(required=True, fulltextindexed=True, maxsize=256) |
|
92 publish_date = Date(default='TODAY') |
|
93 content = String(required=True, fulltextindexed=True) |
|
94 entry_of = SubjectRelation('Blog', cardinality='?*') |
|
95 |
|
96 The first step is the import of the EntityType (generic class for entity and |
|
97 attributes that will be used in both Blog and BlogEntry entities. |
|
98 |
|
99 A Blog has a title and a description. The title is a string that is |
|
100 required and must be less than 50 characters. The |
|
101 description is a string that is not constrained. |
|
102 |
|
103 A BlogEntry has a title, a publish_date and a content. The title is a |
|
104 string that is required and must be less than 100 characters. The |
|
105 publish_date is a Date with a default value of TODAY, meaning that |
|
106 when a BlogEntry is created, its publish_date will be the current day |
|
107 unless it is modified. The content is a string that will be indexed in |
|
108 the database full-text index and has no constraint. |
|
109 |
|
110 A BlogEntry also has a relationship ``entry_of`` that links it to a |
|
111 Blog. The cardinality ``?*`` means that a BlogEntry can be part of |
|
112 zero or one Blog (``?`` means `zero or one`) and that a Blog can |
|
113 have any number of BlogEntry (``*`` means `any number including |
|
114 zero`). For completeness, remember that ``+`` means `one or more`. |
|
115 |
|
116 |
|
117 .. _ExploreYourInstance: |
|
118 |
|
119 Create and explore your instance |
|
120 -------------------------------- |
|
121 .. _CreateYourInstance: |
|
122 |
|
123 Create your instance |
|
124 ~~~~~~~~~~~~~~~~~~~~ |
|
125 |
|
126 To use this cube as an instance and create a new instance named ``blogdemo``, do:: |
|
127 |
|
128 cubicweb-ctl create blog blogdemo |
|
129 |
|
130 This command will create the corresponding database and initialize it. |
|
131 |
|
132 |
|
133 .. _WelcomeToYourWebInstance: |
|
134 |
|
135 Welcome to your web instance |
|
136 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
137 |
|
138 Start your instance in debug mode with the following command: :: |
|
139 |
|
140 cubicweb-ctl start -D blogdemo |
|
141 |
|
142 |
|
143 You can now access your web instance to create blogs and post messages |
|
144 by visiting the URL http://localhost:8080/. |
|
145 |
|
146 A login form will appear. By default, the instance will not allow anonymous |
|
147 users to enter the instance. To login, you need then use the admin account |
|
148 you created at the time you initialized the database with ``cubicweb-ctl |
|
149 create``. |
|
150 |
|
151 .. image:: ../../images/login-form.png |
|
152 |
|
153 |
|
154 Once authenticated, you can start playing with your instance |
|
155 and create entities. |
|
156 |
|
157 .. image:: ../../images/blog-demo-first-page.png |
|
158 |
|
159 Please notice that so far, the *CubicWeb* framework managed all aspects of |
|
160 the web application based on the schema provided at the beginning. |
|
161 |
|
162 .. _AddEntities: |
|
163 |
|
164 Add entities |
|
165 ~~~~~~~~~~~~ |
|
166 |
|
167 We will now add entities in our web application. |
|
168 |
|
169 Add a Blog |
|
170 ********** |
|
171 |
|
172 Let us create a few of these entities. Click on the `[+]` at the left of the |
|
173 link Blog on the home page. Call this new Blog ``Tech-blog`` and type in |
|
174 ``everything about technology`` as the description, then validate the form by |
|
175 clicking on ``Validate``. |
|
176 |
|
177 .. image:: ../../images/cbw-create-blog_en.png |
|
178 :alt: from to create blog |
|
179 |
|
180 Click on the logo at top left to get back to the home page, then |
|
181 follow the Blog link that will list for you all the existing Blog. |
|
182 You should be seeing a list with a single item ``Tech-blog`` you |
|
183 just created. |
|
184 |
|
185 .. image:: ../../images/cbw-list-one-blog_en.png |
|
186 :alt: displaying a list of a single blog |
|
187 |
|
188 Clicking on this item will get you to its detailed description except |
|
189 that in this case, there is not much to display besides the name and |
|
190 the phrase ``everything about technology``. |
|
191 |
|
192 Now get back to the home page by clicking on the top-left logo, then |
|
193 create a new Blog called ``MyLife`` and get back to the home page |
|
194 again to follow the Blog link for the second time. The list now |
|
195 has two items. |
|
196 |
|
197 .. image:: ../../images/cbw-list-two-blog_en.png |
|
198 :alt: displaying a list of two blogs |
|
199 |
|
200 Add a BlogEntry |
|
201 *************** |
|
202 |
|
203 Get back to the home page and click on [+] at the left of the link |
|
204 BlogEntry. Call this new entry ``Hello World`` and type in some text |
|
205 before clicking on ``Validate``. You added a new blog entry without |
|
206 saying to what blog it belongs. There is a box on the left entitled |
|
207 ``actions``, click on the menu item ``modify``. You are back to the form |
|
208 to edit the blog entry you just created, except that the form now has |
|
209 another section with a combobox titled ``add relation``. Chose |
|
210 ``entry_of`` in this menu and a second combobox appears where you pick |
|
211 ``MyLife``. |
|
212 |
|
213 You could also have, at the time you started to fill the form for a |
|
214 new entity BlogEntry, hit ``Apply`` instead of ``Validate`` and the |
|
215 combobox titled ``add relation`` would have showed up. |
|
216 |
|
217 |
|
218 .. image:: ../../images/cbw-add-relation-entryof_en.png |
|
219 :alt: editing a blog entry to add a relation to a blog |
|
220 |
|
221 Validate the changes by clicking ``Validate``. The entity BlogEntry |
|
222 that is displayed now includes a link to the entity Blog named |
|
223 ``MyLife``. |
|
224 |
|
225 .. image:: ../../images/cbw-detail-one-blogentry_en.png |
|
226 :alt: displaying the detailed view of a blogentry |
|
227 |
|
228 Note that all of this was handled by the framework and that the only input |
|
229 that was provided so far is the schema. To get a graphical view of the schema, |
|
230 point your browser to the URL http://localhost:8080/schema |
|
231 |
|
232 .. image:: ../../images/cbw-schema_en.png |
|
233 :alt: graphical view of the schema (aka data-model) |
|
234 |
|
235 |
|
236 .. _DefineViews: |
|
237 |
|
238 Define your entity views |
|
239 ------------------------ |
|
240 |
|
241 Each entity defined in a model is associated with default views |
|
242 allowing different renderings of the data. You can redefine each of |
|
243 them according to your needs and preferences. So let's see how the |
|
244 views are defined. |
|
245 |
|
246 |
|
247 The view selection principle |
|
248 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
249 |
|
250 A view is defined by a Python class which includes: |
|
251 |
|
252 - an identifier (all objects in *CubicWeb* are recorded in a |
|
253 registry and this identifier will be used as a key) |
|
254 |
|
255 - a filter to select the result sets it can be applied to |
|
256 |
|
257 A view has a set of methods complying with the `View` class interface |
|
258 (`cubicweb.common.view`). |
|
259 |
|
260 *CubicWeb* provides a lot of standard views for the type `EntityView`; |
|
261 for a complete list, read the code in directory ``cubicweb/web/views/``. |
|
262 |
|
263 A view is applied on a `result set` which contains a set of entities |
|
264 we are trying to display. *CubicWeb* uses a selector mechanism which |
|
265 computes for each available view a score: the view with the highest |
|
266 score is then used to display the given `result set`. The standard |
|
267 library of selectors is in ``cubicweb.selector``. |
|
268 |
|
269 It is possible to define multiple views for the same identifier |
|
270 and to associate selectors and filters to allow the application |
|
271 to find the most appropriate way to render the data. |
|
272 |
|
273 For example, the view named ``primary`` is the one used to display a |
|
274 single entity. We will now show you how to create a primary view for |
|
275 BlogEntry. |
|
276 |
|
277 |
|
278 Primary view customization |
|
279 ~~~~~~~~~~~~~~~~~~~~~~~~~~ |
|
280 |
|
281 If you wish to modify the way a `BlogEntry` is rendered, you will have |
|
282 to subclass the `primary` view, for instance in the module ``views`` |
|
283 of the cube ``cubes/blog/views.py``. |
|
284 |
|
285 The standard primary view is the most sophisticated view of all. It |
|
286 has more than a call() method. It is a template. Actually the entry |
|
287 point calls the following sequence of (redefinable) methods: |
|
288 |
|
289 * render_entity_title |
|
290 |
|
291 * render_entity_metadata |
|
292 |
|
293 * render_entity_attributes |
|
294 |
|
295 * render_entity_relations |
|
296 |
|
297 * render_side_boxes |
|
298 |
|
299 Excepted side boxes, we can see all of them already in action in the |
|
300 blog entry view. This is all described in more details in |
|
301 :ref:`primary_view`. |
|
302 |
|
303 We can for example add in front of the publication date a prefix |
|
304 specifying that the date we see is the publication date. |
|
305 |
|
306 To do so, please apply the following changes: |
|
307 |
|
308 .. sourcecode:: python |
|
309 |
|
310 from cubicweb.selectors import is_instance |
|
311 from cubicweb.web.views import primary |
|
312 |
|
313 class BlogEntryPrimaryView(primary.PrimaryView): |
|
314 __select__ = is_instance('BlogEntry') |
|
315 |
|
316 def render_entity_attributes(self, entity): |
|
317 self.w(u'<p>published on %s</p>' % |
|
318 entity.publish_date.strftime('%Y-%m-%d')) |
|
319 super(BlogEntryPrimaryView, self).render_entity_attributes(entity) |
|
320 |
|
321 .. note:: |
|
322 When a view is modified, it is not required to restart the instance |
|
323 server. Save the Python file and reload the page in your web browser |
|
324 to view the changes. |
|
325 |
|
326 You can now see that the publication date has a prefix. |
|
327 |
|
328 .. image:: ../../images/cbw-update-primary-view_en.png |
|
329 :alt: modified primary view |
|
330 |
|
331 |
|
332 The above source code defines a new primary view for ``BlogEntry``. |
|
333 |
|
334 Since views are applied to result sets and result sets can be tables of |
|
335 data, we have to recover the entity from its (row,col)-coordinates. |
|
336 The view has a ``self.w()`` method that is used to output data, in our |
|
337 example HTML output. |
|
338 |
|
339 .. note:: |
|
340 You can find more details about views and selectors in :ref:`Views`. |
|
341 |
|
342 |
|
343 .. _DefineEntities: |
|
344 |
|
345 Write entities to add logic in your data |
|
346 ---------------------------------------- |
|
347 |
|
348 By default, CubicWeb provides a default entity for each data type defined in the schema. |
|
349 A default entity mainly contains the attributes defined in the data model. |
|
350 |
|
351 You can redefine each entity to provide additional functions to help you write your views. |
|
352 |
|
353 .. sourcecode:: python |
|
354 |
|
355 from cubicweb.entities import AnyEntity |
|
356 |
|
357 class BlogEntry(AnyEntity): |
|
358 """customized class for BlogEntry entities""" |
|
359 __regid__ = 'BlogEntry' |
|
360 |
|
361 def display_cw_logo(self): |
|
362 if 'CW' in self.title: |
|
363 return True |
|
364 else: |
|
365 return False |
|
366 |
|
367 Customizing an entity requires that your entity: |
|
368 - inherits from ``cubicweb.entities`` or any subclass |
|
369 - defines a ``__regid__`` linked to the corresponding data type of your schema |
|
370 - implements the base class by explicitly using ``__implements__``. |
|
371 |
|
372 We implemented here a function ``display_cw_logo`` which tests if the blog entry title contains 'CW'. |
|
373 This function can then be used when you customize your views. For instance, you can modify your previous ``views.py`` as follows: |
|
374 |
|
375 .. sourcecode:: python |
|
376 |
|
377 class BlogEntryPrimaryView(primary.PrimaryView): |
|
378 __select__ = is_instance('BlogEntry') |
|
379 |
|
380 ... |
|
381 |
|
382 def render_entity_title(self, entity): |
|
383 if entity.display_cw_logo(): |
|
384 self.w(u'<image src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>') |
|
385 super(BlogEntryPrimaryView, self).render_entity_title(entity) |
|
386 |
|
387 Then each blog entry whose title contains 'CW' is shown with the CubicWeb logo in front of it. |
|
388 |
|
389 .. _UpdatingSchemaAndSynchronisingInstance: |
|
390 |
|
391 Updating the schema and synchronising the instance |
|
392 -------------------------------------------------- |
|
393 |
|
394 While developping your cube, you may want to update your data model. Let's say you |
|
395 want to add a ``category`` attribute in the ``Blog`` data type. This is called a migration. |
|
396 |
|
397 The required steps are: |
|
398 |
|
399 1. modify the file ``schema.py``. The ``Blog`` class looks now like this: |
|
400 |
|
401 .. sourcecode:: python |
|
402 |
|
403 class Blog(EntityType): |
|
404 title = String(maxsize=50, required=True) |
|
405 description = String() |
|
406 category = String(required=True, vocabulary=(_('Professional'), _('Personal')), default='Personal') |
|
407 |
|
408 2. stop your ``blogdemo`` instance: |
|
409 |
|
410 .. sourcecode:: bash |
|
411 |
|
412 cubicweb-ctl stop blogdemo |
|
413 |
|
414 3. start the cubicweb shell for your instance by running the following command: |
|
415 |
|
416 .. sourcecode:: bash |
|
417 |
|
418 cubicweb-ctl shell blogdemo |
|
419 |
|
420 4. at the cubicweb shell prompt, execute: |
|
421 |
|
422 .. sourcecode:: python |
|
423 |
|
424 add_attribute('Blog', 'category') |
|
425 |
|
426 5. restart your instance: |
|
427 |
|
428 .. sourcecode:: bash |
|
429 |
|
430 cubicweb-ctl start blogdemo |
|
431 |
|
432 6. modify a blog entity and check that the new attribute |
|
433 ``category`` has been added. |
|
434 |
|
435 Of course, you may also want to add relations, entity types, etc. See :ref:`migration` |
|
436 for a list of all available migration commands. |
|
437 |
|