odoo

Model and view inheritance in odoo

blog image

Inheritance in odoo

# model inheritance
from odoo import api, fields, models, _


class ProductCategory(models.Model):
    _inherit = "product.category"
   
    active = fields.Boolean('Active', default=True)




#view inheritance

<?xml version="1.0" encoding="UTF-8"?>
<odoo>

#tree

    <record id="ecommerce_product_tree_view_inherit" model="ir.ui.view">
        <field name="name">ecommerce.product.tree.view</field>
        <field name="model">product.category</field>
        <field name="inherit_id" ref="product.product_category_list_view"/>
        <field eval="8" name="priority"/>
        <field name="arch" type="xml">
         

            <xpath expr="//field[@name='display_name']" position="after">
                <field name="active"/>
            </xpath>

            <xpath expr="//field[@name='display_name']" position="attributes">
                <attribute name="invisible">0</attribute>
            </xpath>

            <xpath expr="//field[@name='create_date']" position="replace">
                <field name="create_date" optional="hide" readonly="1" />
            </xpath>

        </field>
    </record>  




#form

    <record id="ecommerce_product_form_view_inherit" model="ir.ui.view">
        <field name="name">ecommerce.product.form.view</field>
        <field name="model">product.category</field>
        <field name="inherit_id" ref="product.product_category_form_view"/>
        <field name="arch" type="xml">

            <xpath expr="//field[@name='name']" position="after">
                 <label for="active" string="Active"/>
                <field name="active"  />
            </xpath>

                
            <xpath expr="//field[@name='name']" position="after">
                <field name="description" readonly='1' invisible='1'  />
            </xpath>

            <xpath expr="//notebook//page[@name='contact']" position="attributes">
                <attribute name="invisible">1</attribute>
            </xpath>

            <xpath expr="//div[@name='button_box']" position="attributes">
                <attribute name="invisible">1</attribute>
            </xpath>

           <xpath expr="//button[@name='%(product_template_action_all)d']" position="attributes">
              <attribute name="attrs">{'invisible': [('condition_field', '=', True)]}</attribute>
           </xpath>

           <xpath expr="//group[@name='first']/field[@name='parent_id']" 
                     position="attributes">
            <attribute name="class" ></attribute>
           </xpath>

           <xpath expr="//group[@name='first']" position="attributes">
            <attribute name="col">10</attribute>
          </xpath>


        </field>
    </record>


#kanban

   <record id="ecommerce_product_kanban_inherit" model="ir.ui.view">
        <field name="name">ecommerce.product.kanban</field>
        <field name="model">product.template</field>
        <field name="inherit_id" ref="product.product_template_kanban_view"/>
        <field name="arch" type="xml">
            <xpath expr="//field[@name='priority']" position="attributes">
                <attribute name="invisible">1</attribute>
            </xpath>
            <xpath expr="//div[@name='product_lst_price']" position="attributes">
                <attribute name="invisible">1</attribute>
            </xpath>
            <xpath expr="//field[@name='list_price']" position="attributes">
                <attribute name="invisible">1</attribute>
            </xpath>

        </field>
    </record>

#search

    <record id="focal_scope_product_search_inherit" model="ir.ui.view">
        <field name="name">focal.scope.lead.product.search</field>
        <field name="model">product.template</field>
        <field name="inherit_id" ref="product.product_template_search_view"/>
        <field name="arch" type="xml">
            <xpath expr="//filter[@name='activities_exception']" position="attributes">
                <attribute name="invisible">1</attribute>
            </xpath>
              <xpath expr="//group/filter[@name='type']" position="attributes">
                <attribute name="invisible">1</attribute>
            </xpath>
        </field>
    </record>


</odoo> 

 

 

Odoo framework also supports a few other extension mechanisms that are useful in other cases.

• Delegation inheritance embeds another model in the inheriting one. For example,a User record embeds a Partner record, so that a User record has all the fields available for the Partner records, plus the fields specific to the User records. It is used through the _inherits attribute.


• Prototype inheritance creates a new model by copying the features from the inherited model and has a database table and data. It is not used often and it is never used in the Odoo-included add-on modules. It is used to set _inherit with the model to copy and the _name attribute with the identifier for the new model to be created.

 

• Mixin classes are abstract models that implement generic features that are to be reused in other models. They are like feature containers, ready to be added to other models, and are not expected to be used alone. An example is the mail.thread model, which is provided by the mail add-on module. It implements the chatter and messaging features that are available in several models throughout Odoo, such as Partners and Sales Quotations. A mixin class is constructed from Models. abstract, instead of Models.model, and is used with _inherit.

 

 

Embedding models using delegation inheritance

Delegation inheritance allows us to reuse data structures, without duplication in the database. It embeds an instance of the delegated model inside the inheriting model.

 

Note
To be technically precise, delegation inheritance is not real object inheritance; instead, it is object composition, where some features of an object are delegated to, or provided by, a second object.

 

Note the following about delegation:
• Creating a new model record also creates and links a delegated model record.
• Fields from the delegated model that don't exist in the inheriting model are available for read and write operations, behaving like     related computed fields.

 

Copying models with prototype inheritance


Classic inheritance uses the _inherit attribute to extend a model. Since the _name attribute is not modified, it effectively performs an in-place modification on the same model. If the _name attribute is also modified, along with _inherit, we get a new model that
is a copy of the inherited one. This new model can then have features added to it that are specific to it and won't be added to the parent model. The copied model is independent of the parent model, which will be unaffected by its modifications. It has its own database
table and data. The official documentation calls this prototype inheritance.

 

In practice, there is little benefit in using _inherit to copy a model. Instead, delegation inheritance is preferred, since it reuses data structures without duplicating them. Things become more interesting when we use inheritance from multiple parents. For this,_inherit will be a list of model names, instead of a single name. This can be used to mix several models into one. It allows us to have a model proposing features to be reused several times. This pattern is widely used with abstract mixin classes. This will be discussed in detail in the next section.

 

 

Reusing model features using mixin classes


Setting the _inherit attribute with a list of model names will inherit the features from those models. Most of the time, this is done to leverage mixin classes. A mixin class is like a container of features, meant to be reused. They implement generic features, ready to be added to other models. They are not expected to stand alone and be
used directly. So, they are abstract models, based on models.AbstractModel, with no actual representation in the database, instead of models.Model.

The Odoo standard add-ons propose several useful mixins. Searching the code for models.AbstractModel will reveal them. What's noteworthy, and probably the two most widely used, are these mixins, which are provided by the Discuss app (the mail add-on module):
• The mail.thread mixin provides features for the message board, also known as chatter, which can be found at the bottom or right-hand side of many document forms, along with the logic regarding messages and notifications.
• The mail.activity.mixin mixin provides activities, which are also exposed through the chatter discussion widget, to define and plan to-do tasks.

 

Note:
The activities mixin is a new feature that was introduced in Odoo 11 and is not available in earlier versions.

 

Note:

In this example, the mixins are being added to a new model that is being created now. If we were adding these mixins to an already existing model, which had been created in another module, then the parent model should also be included in the inherited list; for example,
_inherit = ["library.member", "mail.thread",
"mail.activity.mixin"].

 

 

 

Extending views and data


Views and other data components can also be modified by an extension module. For views, the case is usually to add features. The view presentation structure is defined with XML. To extend this XML, we must locate the node to extend and then declare the action
to perform there, such as inserting additional XML elements.The other data elements represent records that were written to the database. Extension modules can write on them to change some values.

 

 

Extending views

Odoo provides a simplified notation to extend XML by using the XML tag we want to match – <field>, for example – with one or more distinctive attributes to match, such as name. Then, we must add the position attribute to declare the kind of modification
to make. Recovering the example we used earlier in this chapter, to add additional content after the isbn field, we can use the following code:

 

<field name="isbn" position="after">
<!-- Changed content goes here -->
</field>


Any XML element and attribute can be used to select the node to use as the extension point, except for string attributes. The values of string attributes are translated into the user's active language during view generation, so they can't be reliably used as node selectors.
The extension operation to perform is declared with the position attribute. Several operations are allowed, as follows:
• inside (the default): Appends the content inside the selected node. The node should be a container, such as <group> or <page>.
• after: Adds the content after the selected node.
• before: Adds the content before the selected node.Extending views and data 
• replace: Replaces the selected node. If it's used with empty content, it deletes the element. Since Odoo 10, it also allows you to wrap an element with other markups by using $0 in the content to represent the element being replaced; for example,

<field name="name" position="replace"><h1>$0</h1></field>.


• attributes: Modifies the attribute values for the matched element. The content should have one or more <attribute name="attr-
name">value<attribute> elements, such as <attribute name="invisible">True></attribute>. If it's used with no body, such
as in <attribute name="invisible"/>, the attribute is removed from the selected element.

Note:
While position="replace" allows us to delete XML elements, this should be avoided. It can break based on modules that may be using the deleted node as an extension point to add other elements. As an alternative, consider leaving the element and making it invisible instead.

 

 

Moving XML nodes to a different location

 


Except for the attributes operation, the preceding locators can be combined with a child element with position="move". The effect is to move the child locator target node to the parent locator's target position.

Changes in Odoo 12
The position="move" child locator is new in Odoo 12 and is not
available in previous versions.

 


Here is an example of moving my_field from its current location to the position after target_field:

<field name="target_field" position="after">
<field name="my_field" position="move"/>
</field>


The other view types, such as list and search views, also have an arch field and can be extended in the same way as form views can.

 

Using XPath to select XML extension points

 


In some cases, we may not have an attribute with a unique value to use as the XML node selector. This can happen when the element to select does not have a name attribute, as is often the case for <group>, <notebook>, or <page> view elements. Another
case is when there are several elements with the same name attribute, as in the case of Kanban QWeb views, where the same field can be included more than once in the same XML template. For these cases, we need a more sophisticated way to locate the XML element to extend.


Being XML, XPath expressions are the natural way to locate elements. For example, taking the book form view we defined in the previous chapter, an
XPath expression for locating the <field name="isbn"> element is //field[@name]='isbn'. This expression finds <field> elements with a name attribute equal to isbn. The XPath equivalent to the book form view extension that we created in the previous
section would be as follows:

<xpath expr="//field[@name='isbn']" position="after">
<field name="is_available" />
</xpath>


More information on the supported XPath syntax can be found in the official Python documentation: https://docs.python.org/3/library/xml.etree. elementtree.html#supported-xpath-syntax. If an XPath expression matches multiple elements, only the first one will be selected as the target for an extension. Therefore, they should be made as specific as possible using
unique attributes. Using the name attribute is the easiest way to ensure that we find the elements we want to use as an extension point. Thus, it is important to have these unique identifiers in the XML elements of the views we create.

 

Modifying existing data

Regular data records can also be extended, which, in practice, means writing over existing values. For this, we just need to identify the record to write on, as well as the fields and values to update. XPath expressions are not needed since we are not modifying XMLarch structures, as we do for views.
The <record id="x" model="y"> data loading elements perform an insert or update operation on model y: if record x does not exist, it is created; otherwise, it is updated/written over.Extending views and data Records in other modules can be accessed using the <module>.<identifier> global identifier, so a module can update a record that's been created by another module.

 

Note:


The dot (.) is reserved to separate the module name from the object identifier. So, it can't be used in identifier names. Instead, use the underscore (_) character. As an example, we will change the name of the User security group to Librarian. The record to modify was created in the library_app module, with the library_app. library_group_user identifier. To do this, we will add the library_member/security/library_security.xml file, along with the following code:

 

<odoo>
<!-- Modify Group name -->
<record id="library_app.library_group_user"
model="res.groups">
<field name="name">Librarian</field>
</record>
</odoo>


Note that we used a <record> element, writing only to the name field. You can think of this as a write operation in this field.
Tip
When using a <record> element, we can select the fields we want to writeon, but the same is not true for shortcut elements, such as <menuitem> and <act_window>. These need all of the attributes to be provided and missing any of them will set the corresponding field to an empty value. However, you can use <record> to set a value on a field that was created through a shortcut element.
Don't forget to add the library_member/security/library_security.xml file to the data key in the manifest file. Having done this and upgraded the module, we should see the name change in the user groups.

 

 

Extending views allows you to introduce modifications to the backend presentation layer. But the same can be done to the frontend web presentation layer. This is what we will address in the next section.

 

 

Extending Web pages

 

Extending QWeb templates

 

 

 

 

 

 

Importing, Exporting, and Module Data

 

Most Odoo module definitions, such as user interfaces and security rules, are data records that are stored in specific database tables. The XML and CSV files that are found in modules are not used by Odoo applications at runtime. They are a means of loading
those definitions into database tables. Because of this, an important part of Odoo modules is representing data in files so that it
can be loaded into a database upon module installation. Modules can also contain initial data and demonstration data. Data files allow us to add that to our modules.


Additionally, understanding Odoo data representation formats is important for exporting and importing business data within the context of a project's implementation.The following topics will be covered in this chapter:
• Understanding the external identifier concept
• Exporting and importing data files
• Using CSV files
• Adding module data
• Using XML data files

 

Exporting and importing CSV data files

 

 

 

Related records in CSV data files

 

id, name, author_ids/id
book_odc11, "Odoo 11 Development Cookbook", "__export__.res_
partner_43_f82d2ecc,__export__.res_partner_44_6be5a130"




"id","name","child_ids/id","child_ids/name"
"base.res_partner_12","Azure Interior","base.res_partner_
address_15","Brandon Freeman"
"","","base.res_partner_address_28","Colleen Diaz"
"","","base.res_partner_address_16","Nicole Ford"

 

 

 

Using XML data files

 

 

Traditional Class Inheritance

from odoo import models, api

class IrAttachment(models.Model):
    _inherit = 'ir.attachment'

 

Delegation inheritance

In Odoo, delegation inheritance is a method used to extend an existing model by creating a new model that delegates some of its functionality to the parent model. This is different from classical inheritance where the child model inherits all fields and methods from the parent model. Delegation inheritance allows you to create a new model that can reference the parent model and utilize its fields and methods without directly inheriting them.

How Delegation Inheritance Works in Odoo

In delegation inheritance, you create a new model with a many-to-one relationship to the parent model. This new model can access the parent model's fields and methods through this relationship

 

from odoo import models,api,fields

class Student(models.Model):
    _name = 'school.student'
    _description = 'Student Inforamtion'
    _rec_name = 'name'
    _order = 'name ASC'

    name = fields.Char(
        string='Name',
        required=True,
        copy=False
    )
    email=fields.Char(string='Email',required=True)
    gender=fields.Selection([('male','male'),('female','female')],string='Gender')
    
    
class StudentExtraInfo(models.Model):
    _name='school.student.extra'
    _dewcription='Student extra information'
    _inherits={'school.student':'student_id'}
    
    student_id=fields.Many2one('school.student','Student')
    age=fields.Integer(string='Age')
    country=fields.Many2one('res.country',"Country")
    is_single=fields.Boolean(required=True)

 

Explanation

  1. Parent Model: The school.student model represents general  information such as name, email, and gender.
  2. Child Model: The school.student.extra model represents extra information and uses the _inherits attribute to inherit fields from the  school.student  model.

The _inherits attribute creates a many-to-one relationship with the school.student model using the  student _id field. This allows the school.student.extra model to access the fields of the  school.student  model.

 

<record id="school_student_extra_view_form" model="ir.ui.view">
    <field name="name">school.student.extra.view.form</field>
    <field name="model">school.student.extra</field>
    <field name="arch" type="xml">
        <form string="">
            <sheet>
                <group>
                <group>
                    <field name="name" />
                    <field name="email" />
                    <field name="gender" />
                </group>
                <group>
                      <field name="student_id" readonly='1' />
                      <field name="age" />
                    <field name="country" />
                    <field name="is_single" />
                </group>
                </group>
            </sheet>
        </form>
    </field>
</record>

 

 

How data is store in database:
school_student_extra  table

school_student table:

 

 

 

Different way to inherit the view in odoo

<record id="inherit_view_id_inherit_module_name" model="ir.ui.view">
    <field name="name">model.name.view.form.inherit</field>
    <field name="model">model.name</field>
    <field name="inherit_id" ref="inherit_module_name.inherit_view_id"/>
    <field name="arch" type="xml">


        <xpath expr="//field[@name='vat]" position="after">
            <field name="country" />
            <field name="name" />
            <field name="age" />
        </xpath>
        
    </field>
</record>



 

 

 


About author

author image

Amrit Panta

Python developer, content writer



3 Comments

Amanda Martines 5 days ago

Exercitation photo booth stumptown tote bag Banksy, elit small batch freegan sed. Craft beer elit seitan exercitation, photo booth et 8-bit kale chips proident chillwave deep v laborum. Aliquip veniam delectus, Marfa eiusmod Pinterest in do umami readymade swag. Selfies iPhone Kickstarter, drinking vinegar jean.

Reply

Baltej Singh 5 days ago

Drinking vinegar stumptown yr pop-up artisan sunt. Deep v cliche lomo biodiesel Neutra selfies. Shorts fixie consequat flexitarian four loko tempor duis single-origin coffee. Banksy, elit small.

Reply

Marie Johnson 5 days ago

Kickstarter seitan retro. Drinking vinegar stumptown yr pop-up artisan sunt. Deep v cliche lomo biodiesel Neutra selfies. Shorts fixie consequat flexitarian four loko tempor duis single-origin coffee. Banksy, elit small.

Reply

Leave a Reply

Scroll to Top