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