Many2many fields are similar to Many2one fields in that they establish a new relationship between models. In Odoo 16, you cannot group by many2many fields since any records can be selected using many2many records. You will encounter an assertion error when you give a group by filter utilizing a many2many field.
This blog will provide insight into how to use the group for Many2Many fields in Odoo 16.
Here, I will be using the already-existing tag_ids many2many field. As demonstrated in the code below:
.py
tag_ids = fields.Many2many('crm.tag', 'sale_order_tag_rel', 'order_id', 'tag_id', string='Tags')
.xml
<record id="view_sales_order_filter" model="ir.ui.view">
<field name="name">sale.order.view.list.inherit.module.name</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_sales_order_filter"/>
<field name="arch" type="xml">
<xpath expr="//search/group/filter[@name='customer']" position="after">
<separator/>
<filter name="tag_ids" string="Tags" domain="[]" context="{'group_by': 'tag_ids'}"/>
<separator/>
</xpath>
</field>
</record>
It is possible to do group_by filter using the Many2many field. It will be possible if we compute the field but if the value is two in many2many fields then it will be shown by comma (,)like tag1,tag2, etc since it is a char field.
.py
product_tags = fields.Char(string='Tags', compute='_get_tags', store=True)
@api.model
@api.depends('tag_ids')
def _get_tags(self):
for rec in self:
if rec.tag_ids:
product_tags = ','.join([p.name for p in rec.tag_ids])
else:
product_tags = ''
rec.product_tags = product_tags
.xml
<record id="view_sales_order_filter" model="ir.ui.view">
<field name="name">sale.order.view.list.inherit.module.name</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_sales_order_filter"/>
<field name="arch" type="xml">
<xpath expr="//search/group/filter[@name='customer']"
position="after">
<separator/>
<filter name="tag_ids" string="Tags" domain="[]"
context="{'group_by': 'product_tags'}"/>
<separator/>
</xpath>
</field>
</record>
<record id="sale_view_form_custom" model="ir.ui.view">
<field name="name">ale.order.view.form.inherit.module.name</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<xpath expr="//field[@name='payment_term_id']" position="after">
<field name="product_tags"/>
</xpath>
</field>
</record>
Here we added a Char field product_tags. It is a computed field, which joins the tag name into that field.
You can see there is a group by filter named Tags that we gave in the XML file. When we try to group by these sales orders it will be shown below.
Likewise, we can add groupby for many2many fields.
Next, let's check how to add a filter for many2many fields.
You can create a substitute Many2Many field to calculate the value from many2many fields. I'll provide an example to demonstrate this. The field must have store=True specified in it.
.py
newfield_id = fields.Many2one('example_ids', compute=_compute_newfield_id, store=True)
@api.depends('example_ids')
def _compute_newfield_id(self):
for record in self:
record.newfield_id = record.example_ids and record.example_ids[0] or False
.xml
<field name="newfield_id" string="Example" filter_domain="[(newfield_id,'ilike', self)]"/>
You can provide the domain according to your requirements because it is possible to search simply among saved fields. The location's xpath can be included if you like.
To read more about creating many2many field in the customer portal form in Odoo 16, refer to our blog How to Create Many2Many Field in the Customer Portal Form in Odoo 16