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