Adding a hierarchy to a Model

Hierarchies are represented using model relations with itself; each record has a parent record in the same model and also has many child records. This can be achieved by simply using many-to-one relations between the model and itself.

But Odoo also provides improved support for this type of field using the Nested set model (https://en.wikipedia.org/wiki/Nested_set_model). When activated, queries using the child_of operator in their domain filters will run significantly faster.

Staying with the Library Books example, we will build a hierarchical category tree that could be used to categorize books.

Getting ready

We will reuse the my_module addon module from Chapter 3, Creating Odoo Modules.

How to do it…

We will add a new Python file, models/library_book_categ.py, for the category tree, shown as follows:

  1. To have the new Python code file loaded, add this line to models/__init__.py:
    from . import library_book_categ
  2. To create the Book Category model with the parent and child relations, create the models/library_book_categ.py file with the following:
    # -*- coding: utf-8 -*-
    from openerp import models, fields, api
    class BookCategory(models.Model):
        _name = 'library.book.category'
        name = fields.Char('Category')
        parent_id = fields.Many2one(
            'library.book.category',
            string='Parent Category',
            ondelete='restrict',
            index=True)
        child_ids = fields.One2many(
            'library.book.category', 'parent_id',
            string='Child Categories')
  3. To enable the special hierarchy support, also add the following:
    _parent_store = True
    parent_left = fields.Integer(index=True)
    parent_right = fields.Integer(index=True)
  4. To add a check preventing looping relations, add the following line to the model:
    @api.constrains('parent_id')
    def _check_hierarchy(self):
        if not self._check_recursion():
            raise models.ValidationError(
                'Error! You cannot create recursive categories.')

Finally, a module upgrade should make these changes effective.

How it works…

Steps 1 and 2 create the new model with hierarchic relations. The Many2one relation adds a field to reference the parent record. For faster child record discovery, this field is indexed in the database using the index=True parameter. The parent_id field must have ondelete set to either 'cascade' or 'restrict'.

At this point, we have all that is required to have a hierarchic structure. But there are a few more additions we can make to enhance it.

The One2many relation does not add any additional fields to the database but provides a shortcut to access all the records with this record as their parent.

In step 3, we activate the special support for hierarchies. This is useful for high-read but low-write instructions, since it brings faster data browsing at the expense of costlier write operations. It is done by adding two helper fields, parent_left and parent_right, and setting the model attribute to _parent_store=True. When this attribute is enabled, the two helper fields will be used to store data in searches in the hierarchic tree.

By default, it is assumed that the field for the record's Parent is called parent_id, but a different name can be used. In that case, the correct field name should be indicated using the additional model attribute _parent_name. The default is as follows:

    _parent_name = 'parent_id'

Step 4 is advised in order to prevent cyclic dependencies in the hierarchy— that is, having a record both in the ascending and descending trees. This is dangerous for programs that navigate through the tree, since they can get into an infinite loop. The models.Model provides a utility method for this (_check_recursion) that we have reused here.

There's more…

The technique shown here should be used for "static" hierarchies, which are read and queried often but seldom updated. Book categories are a good example, since the Library will not be continuously creating new categories, but readers will often be restricting their searches to a category and all its children categories. The reason for this lies in the implementation of the Nested Set Model in the database, which requires an update of the parent_left and parent_right columns (and the related database indexes) for all records whenever a category is inserted, removed, or moved. This can be a very expensive operation, especially when multiple editions are being performed in parallel transactions.

If you are dealing with a very dynamic hierarchical structure, the standard parent_id and child_ids relations can result in better performance.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.145.154.185