Mixins are abstract models that provide useful features through inheritance. They do not have an actual representation in the database. Instead, they provide some set of features that can be mixed with other models. By default the Odoo addons provide several mixins, some of the commonly used mixins are, ‘mail.thread’, ‘mail.activity.mixin’, ‘rating.mixin’, etc.
In this blog, we are going to explain those mixins and their use cases.
Message Features
Integration of Messaging
Integration of messaging features to our custom model is an easier way. By inheriting the mail.thread model in our custom model and by adding the messaging fields in the form view of the custom model, we can use the messaging features. Next, we are going to explain how it can be done.
models.py:
from odoo import models, api, fields
class LibraryBook(models.Model):
_name = 'library.book'
_inherit = ['mail.thread']
_description = 'Library Book'
name = fields.Char()
partner_id = fields.Many2one('res.partner', 'Taken By')
date = fields.Date()
views.xml:
<record id="library_book_form" model="ir.ui.view">
<field name="name">library.book.form</field>
<field name="model">library.book</field>
<field name="arch" type="xml">
<form string="Library Book">
<sheet>
<group>
<field name="name"/>
<field name="partner_id"/>
<field name="date"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
The output is as follows,
In the above given example, the library.book is our custom model. We need to add the messaging feature for the library.book. For that, first, we inherit the mail.thread model inside the library.book. Then add the messaging fields to the form view. After the users are able to use the messaging features such as adding log note, and send messages inside the library book. When a user adds a message, every time it will send a notification to all the followers of the record, and internal notes send to the employee user. If we correctly configured the mail gateway and catchall address, then the message and internal note notifications are also sent by email and can be replied directly from the client mail, automatic routing system will route the answer to the correct thread.
Logging Changes
The mail module adds powerful features to the fields of the models, which allows you to track the changes of the specific field in the record’s chatter. It can be achieved by adding the tracking attribute of the field as True. Following is an example.
from odoo import models, api, fields
class LibraryBook(models.Model):
_name = 'library.book'
_inherit = ['mail.thread']
_description = 'Library Book'
name = fields.Char()
partner_id = fields.Many2one('res.partner', 'Taken By', tracking=True)
date = fields.Date()
Here, we have set the tracking = True for the field partner_id. Below given is a record created in the model ‘library.book’ with a partner.
If we change the field Taken by then, the output will be as given below
Activities Tracking
Activities are actions to be taken by the user on records like scheduling a meeting, making phone calls, etc. Activities come with the mail module but are not bundled with the mail.thread model. They are the records of the mail.activity model, which has a type, name, description, and scheduled time. Above the message history in the chatter widget, we are able to see the activities that are pending on records. To integrate the activity features into the custom model we need to inherit the mail.activity.mixin class inside our model and the specific widget like mail_activity and kanban_activity to display them in the form view and in the kanban view of the model. The following is an example of integrating the mail.activity in the custom model:
from odoo import models, api, fields
class LibraryBook(models.Model):
_name = 'library.book'
_inherit = ['mail.thread', 'mail.activity.mixin']
_description = 'Library Book'
name = fields.Char()
partner_id = fields.Many2one('res.partner', 'Taken By', tracking=True)
date = fields.Date()
The form view is defined as follows:-
<record id="library_book_form" model="ir.ui.view">
<field name="name">library.book.form</field>
<field name="model">library.book</field>
<field name="arch" type="xml">
<form string="Library Book">
<sheet>
<group>
<field name="name"/>
<field name="partner_id"/>
<field name="date"/>
</group>
</sheet>
<div class="oe_chatter">
<field name="message_follower_ids" widget="mail_followers"/>
<field name="activity_ids" widget="mail_activity"/>
<field name="message_ids" widget="mail_thread"/>
</div>
</form>
</field>
</record>
First, we have inherited the mail.activity.mixin in the custom mode library.book. After that, added the field activity_ids inside the form view with widget mail_activity.
By clicking on the Schedule activity, we are able to schedule activities such as mail, call, meeting, etc., on our records.
Website Features
Visitor Tracking
Another mixin provided by Odoo is utm.mixin. By using the argument that links to the specified resources, this mixin is used to track online marketing/communication campaigns. The utm.mixin adds 3 fields to our custom model:
campaign_id – which is a Many2one field to the utm.campaign object
source_id – which is a Many2one field to the utm.source object
medium_id – which is a Many2one field to the utm.medium object
When a customer visits your website these parameters are set in the URL like https://www.odoo.com/?campaign_id=mixin_talk&source_id=www.odoo.com&medium_id=website , In the visitor’s website, there are three cookies are set for these 3 fields. Once a custom model inherits the utm.mixin, the utm.mixin code kicks in and fetches the values from the cookies set on the visitor’s website to add them to the new records. Once we set the values, we can use these three fields as any other fields when creating reports and views.
Website Visibility
We can easily add the website visibility toggle on any of our records. The website.published.mixin is used for this purpose. The website.published.mixin is mainly used for the object which has a frontend page.
class LibraryBook(models.Model):
_name = "library.book"
_description = "Library Book"
_inherit = ['website.published.mixin']
To achieve this functionality we only need to inherit the website.published.mixin on our model as given above. This adds two fields to our model:-
website_published – which is a Boolean field, that represents the status of the publication.
website_url – A Char field that is used to represent the URL through the object accessed. This is a computed field, and the compute function must be implemented in the custom object.
def _compute_website_url(self):
for blog_post in self:
blog_post.website_url = "/blog/%s" % (log_post.blog_id)
Once it is done, the next step is to adapt our frontend and backend views to make it accessible. In the backend view, usually, we need to add a button in the button box, as given below:
<button class="oe_stat_button" name="website_publish_button"
type="object" icon="fa-globe">
<field name="website_published" widget="website_button"/>
</button>
In the frontend, we need some security checks to avoid the editing button access to the website visitor’s. It will be added as follows:-
<div id="website_published_button" class="float-right"
groups="base.group_website_publisher"> <!-- or any other meaningful group -->
<t t-call="website.publish_management">
<t t-set="object" t-value="blog_post"/>
<t t-set="publish_edit" t-value="True"/>
<t t-set="action" t-value="'blog.blog_post_action'"/>
</t>
</div>
Customer Rating
The rating.mixin is used for customer rating purposes. It allows sending emails to collect customer ratings, automatic transitioning in a kanban process, and aggregating statistics on the rating. We need to inherit the ‘rating.mixin’ model inside our custom model for adding the rating. An example of adding a rating is as follows:
class MyModel(models.Models):
_name = library.book
_inherit = ['rating.mixin', 'mail.thread']
user_id = fields.Many2one('res.users', 'Responsible')
partner_id = fields.Many2one('res.partner', 'Customer')
The behavior of this mixin adapts to the custom model as,
1) The rating.rating record is linked to the partner_id field of our custom model if it exists in the model. Otherwise it will be overridden by the function rating_get_partner_id().
2) The rating.rating record is linked to the partner of the user_id field of our custom model if it is present. Otherwise this will be overridden by the function rating_get_rated_partner_id().
3) The rating event will be displayed in the chatter history if the custom model inherits mail.thread.
We are able to integrate the rating with the form view by defining an action for the rating. For example:
<record id="rating_rating_action_book" model="ir.actions.act_window">
<field name="name">Customer Ratings</field>
<field name="res_model">rating.rating</field>
<field name="view_mode">kanban,pivot,graph</field>
<field name="domain">[('res_model', '=', library.book), ('res_id', '=', active_id), ('consumed', '=', True)]</field>
</record>
<record id=”library_book_view_form_inherit_rating" model="ir.ui.view">
<field name="name">library.view.form.inherit.rating</field>
<field name="model">library.book</field>
<field name="inherit_id" ref="library.library_book_view_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button name="%(rating_rating_action_my_model)d" type="action"
class="oe_stat_button" icon="fa-smile-o">
<field name="rating_count" string="Rating" widget="statinfo"/>
</button>
</xpath>
</field>
</record>
There are default views (kanban, pivot, graph) for ratings which allow you a quick view of your rating. Some of the examples of integration of rating.mixin are project.task in the Project, helpdesk.ticket in the helpdesk. These are some of the main use cases of mixins.