1.2. Steps for creating your cube — CubicWeb 3.10.1

### Navigation

- index
- modules |
- next |
- previous |
- CubicWeb 3.10.1 »
- Tutorials »
- 1. Building a simple blog »

# 1.2. Steps for creating your cube

The following steps will help you to create and customize a new cube.

1. Create your cube

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:

> - schema.py: contains the data model
> - views.py: contains your custom views
> - entities.py: contains XXX

The detailed structure of the code directory is described in Standard structure for a cube.

2. Define your data model

Define the data model of your application.

3. Create and explore your instance

Create, run, and explore an instance of your cube.

4. Define your entity views

Customize the views of your data: how and which part of your data are showed.

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/’.

5. Write entities to add logic in your data

Define your own entities to add useful functions when you manipulate your data, especially when you write view.

# 1.3. Create your cube

The packages `cubicweb` and `cubicweb-dev` install a command line tool for CubicWeb called `cubicweb-ctl`. This tool provides a wide range of commands described in details in cubicweb-ctl tool.

Once your CubicWeb development environment is set up, you can create a new cube:

    cubicweb-ctl newcube blog

This will create in the cubes directory (`/path/to/forest/cubes` for Mercurial installation, `/usr/share/cubicweb/cubes` for debian packages installation) a directory named `blog` reflecting the structure described in The Core Concepts of CubicWeb.

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:

    CW_CUBES_PATH=~/src/cubes
    CW_MODE=user

and then create your new cube using:

    cubicweb-ctl newcube --directory=~/src/cubes blog

# 1.4. Define your data model

The data model or schema is the core of your CubicWeb application. It defines the type of content your application will handle.

The data model of your cube `blog` is defined in the file `schema.py`:

    from yams.buildobjs import EntityType, String, SubjectRelation, Date

    class Blog(EntityType):
      title = String(maxsize=50, required=True)
      description = String()

    class BlogEntry(EntityType):
      title = String(required=True, fulltextindexed=True, maxsize=256)
      publish_date = Date(default='TODAY')
      content = String(required=True, fulltextindexed=True)
      entry_of = SubjectRelation('Blog', cardinality='?*')

The first step is the import of the EntityType (generic class for entity and attributes that will be used in both Blog and BlogEntry entities.

A Blog has a title and a description. The title is a string that is required and must be less than 50 characters. The description is a string that is not constrained.

A BlogEntry has a title, a publish_date and a content. The title is a string that is required and must be less than 100 characters. The publish_date is a Date with a default value of TODAY, meaning that when a BlogEntry is created, its publish_date will be the current day unless it is modified. The content is a string that will be indexed in the database full-text index and has no constraint.

A BlogEntry also has a relationship `entry_of` that links it to a Blog. The cardinality `?*` means that a BlogEntry can be part of zero or one Blog (`?` means zero or one) and that a Blog can have any number of BlogEntry (`*` means any number including zero). For completeness, remember that `+` means one or more.

# 1.5. Create and explore your instance

## 1.5.1. Create your instance

To use this cube as an instance and create a new instance named `blogdemo`, do:

    cubicweb-ctl create blog blogdemo

This command will create the corresponding database and initialize it.

## 1.5.2. Welcome to your web instance

Start your instance in debug mode with the following command:

    cubicweb-ctl start -D blogdemo

You can now access your web instance to create blogs and post messages by visiting the URL http://localhost:8080/.

A login form will appear. By default, the instance will not allow anonymous users to enter the instance. To login, you need then use the admin account you created at the time you initialized the database with `cubicweb-ctl create`.

Once authenticated, you can start playing with your instance and create entities.

Please notice that so far, the CubicWeb framework managed all aspects of the web application based on the schema provided at the beginning.

## 1.5.3. Add entities

We will now add entities in our web application.

### 1.5.3.1. Add a Blog

Let us create a few of these entities. Click on the [+] at the left of the link Blog on the home page. Call this new Blog `Tech-blog` and type in `everything about technology` as the description, then validate the form by clicking on `Validate`.

Click on the logo at top left to get back to the home page, then follow the Blog link that will list for you all the existing Blog. You should be seeing a list with a single item `Tech-blog` you just created.

Clicking on this item will get you to its detailed description except that in this case, there is not much to display besides the name and the phrase `everything about technology`.

Now get back to the home page by clicking on the top-left logo, then create a new Blog called `MyLife` and get back to the home page again to follow the Blog link for the second time. The list now has two items.

### 1.5.3.2. Add a BlogEntry

Get back to the home page and click on [+] at the left of the link BlogEntry. Call this new entry `Hello World` and type in some text before clicking on `Validate`. You added a new blog entry without saying to what blog it belongs. There is a box on the left entitled `actions`, click on the menu item `modify`. You are back to the form to edit the blog entry you just created, except that the form now has another section with a combobox titled `add relation`. Chose `entry_of` in this menu and a second combobox appears where you pick `MyLife`.

You could also have, at the time you started to fill the form for a new entity BlogEntry, hit `Apply` instead of `Validate` and the combobox titled `add relation` would have showed up.

Validate the changes by clicking `Validate`. The entity BlogEntry that is displayed now includes a link to the entity Blog named `MyLife`.

Note that all of this was handled by the framework and that the only input that was provided so far is the schema. To get a graphical view of the schema, point your browser to the URL http://localhost:8080/schema

# 1.6. Define your entity views

Each entity defined in a model is associated with default views allowing different renderings of the data. You can redefine each of them according to your needs and preferences. So let’s see how the views are defined.

## 1.6.1. The view selection principle

A view is defined by a Python class which includes:

> - an identifier (all objects in CubicWeb are recorded in a registry and this identifier will be used as a key)
> - a filter to select the result sets it can be applied to

A view has a set of methods complying with the View class interface (cubicweb.common.view).

CubicWeb provides a lot of standard views for the type EntityView; for a complete list, read the code in directory `cubicweb/web/views/`.

A view is applied on a result set which contains a set of entities we are trying to display. CubicWeb uses a selector mechanism which computes for each available view a score: the view with the highest score is then used to display the given result set. The standard library of selectors is in `cubicweb.selector`.

It is possible to define multiple views for the same identifier and to associate selectors and filters to allow the application to find the most appropriate way to render the data.

For example, the view named `primary` is the one used to display a single entity. We will now show you how to create a primary view for BlogEntry.

## 1.6.2. Primary view customization

If you wish to modify the way a BlogEntry is rendered, you will have to subclass the primary view, for instance in the module `views` of the cube `cubes/blog/views.py`.

The standard primary view is the most sophisticated view of all. It has more than a call() method. It is a template. Actually the entry point calls the following sequence of (redefinable) methods:

> - render_entity_title
> - render_entity_metadata
> - render_entity_attributes
> - render_entity_relations
> - render_side_boxes

Excepted side boxes, we can see all of them already in action in the blog entry view. This is all described in more details in The Primary View.

We can for example add in front of the publication date a prefix specifying that the date we see is the publication date.

To do so, please apply the following changes:

    from cubicweb.selectors import is_instance
    from cubicweb.web.views import primary

    class BlogEntryPrimaryView(primary.PrimaryView):
        __select__ = is_instance('BlogEntry')

        def render_entity_attributes(self, entity):
            self.w(u'<p>published on %s</p>' %
                   entity.publish_date.strftime('%Y-%m-%d'))
            super(BlogEntryPrimaryView, self).render_entity_attributes(entity)

Note

When a view is modified, it is not required to restart the instance server. Save the Python file and reload the page in your web browser to view the changes.

You can now see that the publication date has a prefix.

The above source code defines a new primary view for `BlogEntry`.

Since views are applied to result sets and result sets can be tables of data, we have to recover the entity from its (row,col)-coordinates. The view has a `self.w()` method that is used to output data, in our example HTML output.

Note

You can find more details about views and selectors in Principles.

# 1.7. Write entities to add logic in your data

By default, CubicWeb provides a default entity for each data type defined in the schema. A default entity mainly contains the attributes defined in the data model.

You can redefine each entity to provide additional functions to help you write your views.

    from cubicweb.entities import AnyEntity

    class BlogEntry(AnyEntity):
        """customized class for BlogEntry entities"""
        __regid__ = 'BlogEntry'

        def display_cw_logo(self):
            if 'CW' in self.title:
                return True
            else:
                return False

Customizing an entity requires that your entity:
  - inherits from `cubicweb.entities` or any subclass
  - defines a `__regid__` linked to the corresponding data type of your schema
  - implements the base class by explicitly using `__implements__`.

We implemented here a function `display_cw_logo` which tests if the blog entry title contains ‘CW’. This function can then be used when you customize your views. For instance, you can modify your previous `views.py` as follows:

    class BlogEntryPrimaryView(primary.PrimaryView):
        __select__ = is_instance('BlogEntry')

        ...

        def render_entity_title(self, entity):
            if entity.display_cw_logo():
                self.w(u'<image src="http://www.cubicweb.org/doc/en/_static/cubicweb.png"/>')
            super(BlogEntryPrimaryView, self).render_entity_title(entity)

Then each blog entry whose title contains ‘CW’ is shown with the CubicWeb logo in front of it.

# 1.8. Updating the schema and synchronising the instance

While developping your cube, you may want to update your data model. Let’s say you want to add a `category` attribute in the `Blog` data type. This is called a migration.

The required steps are:

1. modify the file `schema.py`. The `Blog` class looks now like this:

    class Blog(EntityType):
      title = String(maxsize=50, required=True)
      description = String()
      category = String(required=True, vocabulary=(_('Professional'), _('Personal')), default='Personal')

2. stop your `blogdemo` instance:

    cubicweb-ctl stop blogdemo

3. start the cubicweb shell for your instance by running the following command:

    cubicweb-ctl shell blogdemo

4. at the cubicweb shell prompt, execute:

    add_attribute('Blog', 'category')

5. restart your instance:

    cubicweb-ctl start blogdemo

6. modify a blog entity and check that the new attribute `category` has been added.

Of course, you may also want to add relations, entity types, etc. See Migration for a list of all available migration commands.

### Navigation

- index
- modules |
- next |
- previous |
- CubicWeb 3.10.1 »
- Tutorials »
- 1. Building a simple blog »