Extending the to-do task model

New models are defined through Python classes. Extending them is also done through Python classes, but using an Odoo specific mechanism.

To extend an existing model we use a Python class with a _inherit attribute. This identifies the model to be extended. The new class inherits all the features of the parent Odoo model, and we only need to declare the modifications that we wish to introduce.

In fact, Odoo models exist outside our particular module, in a central registry. This registry can also be referred to as the pool, and can be accessed from model methods using self.env[<model name>]. For example, to reference the res.partner model we would write self.env['res.partner'].

To modify an Odoo model we get a reference to its registry class and then perform in place changes on it. This means that these modifications will also be available everywhere else where the model is used.

In the module loading sequence, during a server start, modifications will only be visible to the modules loaded afterward. So, the loading sequence is important and we should make sure that the module dependencies are correctly set.

Adding fields to a model

We will extend the todo.task model to add a couple of fields to it: the user responsible for the task, and a deadline date.

Create a new todo_task.py file declaring a class extending the original model:

# -*- coding: utf-8 -*-
from openerp import models, fields, api
class TodoTask(models.Model):
    _inherit = 'todo.task'
    user_id = fields.Many2one('res.users', 'Responsible')
    date_deadline = fields.Date('Deadline')

The class name is local to this Python file, and in general is irrelevant for other modules. The _inherit class attribute is the key here: it tells Odoo that this class is inheriting from the todo.task model. Notice the _name attribute absent. It is not needed because it is already inherited from the parent model.

The next two lines are regular field declarations. The user_id represents a user from the Users model, res.users. It's a Many2one field, the equivalent to a foreign key in database jargon. The date_deadline is a simple date field. In Chapter 5, Models – Structuring the Application Data we will be explaining in more detail the types of fields available in Odoo.

We still need to add to the __init__.py file the import statement to include it in the module:

from . import todo_task

To have the new fields added to the model's supporting database table we need to perform a module upgrade. If everything goes as expected, you should see the new fields when inspecting the todo.task model, in the Technical menu, Database Structure | Models option.

Modifying existing fields

As you can see, adding new fields to an existing model is quite straightforward. Since Odoo 8, modifying attributes on already existing fields is also possible. It's done by adding a field with the same name, and setting values only for the attributes to be changed.

For example, to add a help tooltip to the name field, we could add this line to the todo_ task.py described above:

name = fields.Char(help="What needs to be done?")

If we upgrade the module, go to a to-do task form, and pause the mouse pointer over the Description field, the above tooltip text will be displayed.

Modifying model's methods

Inheritance also works at the business logic level. Adding new methods is simple: just declare their functions inside the inheriting class.

To extend existing logic, the corresponding method can be overridden by declaring a method with the exact same name, and the new method will replace the previous one. But it can extend the code of the inherited class, by using Python's super() keyword to call the parent method.

It's best to avoid changing the method's function signature (that is, keep the same arguments) to be sure that the existing calls on it will keep working properly. In case you need to add additional parameters, make them optional (with a default value) keyword arguments.

The original Clear All Done action is not appropriate for our task-sharing module anymore, since it clears all tasks regardless of their user. We need to modify it so that it clears only the current user tasks.

For this, we will override the original method with a new version that first finds the list of completed tasks for the current user, and then inactivates them:

    @api.multi
    def do_clear_done(self):
      domain = [('is_done', '=', True),
        '|', ('user_id', '=', self.env.uid),
        ('user_id', '=', False)]
      done_recs = self.search(domain)
      done_recs.write({'active': False})
return True

We first list the done records to act upon using the search method with a filter expression. The filter expression follows an Odoo specific syntax referred to as a domain.

The filter domain used is defined the first instruction: it is a list of conditions, where each condition is a tuple.

These conditions are implicitly joined with an AND operator ('&' in domain syntax). To add an OR operation a pipe ('|') is used in place of a tuple, and it will affect the next two conditions. We will go into more details about domains in Chapter 6, Views - Designing the User Interface.

The domain used here filters all done tasks ('is_done', '=', True) that either have the current user as responsible ('user_id', '=', self.env.uid) or don't have a current user set ('user_id', '=', False).

What we just did was to completely overwrite the parent method, replacing it with a new implementation.

But this is not what we usually want to do. Instead we should extend the existing logic to add some additional operations to it. Otherwise we could break already existing features. Existing logic is inserted in an overriding method using Python's super() command, to call the parent's version of the method.

Let's see an example of this: we could write a better version of do_toggle_done() that only performs its action on the Tasks assigned to our user:

    @api.one
    def do_toggle_done(self):
        if self.user_id != self.env.user:
            raise Exception('Only the responsible can do this!')
        else:
            return super(TodoTask, self).do_toggle_done()

These are the basic techniques for overriding and extending business logic defined in model classes. Next we will see how to extend the user interface views.

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

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