ORM в Odoo — мощный инструмент, но разработчики часто сталкиваются с трудностями при группировке записей по полю типа Many2Many. Поля M2M работают иначе, чем обычные поля базы данных: значения хранятся не непосредственно в основной таблице, а в реляционной таблице. Из-за этого Odoo не может применять к ним свою обычную логику « GROUP BY », что приводит к ошибкам утверждения при попытке группировки непосредственно по полю M2M.
Надежным обходным путем является создание вычисляемого, хранимого поля, представляющего значения M2M в простом формате (обычно это строка, разделенная запятыми). После того, как это поле появится в базе данных , оно станет доступным для группировки в представлениях поиска.
Ниже приведён практический пример, основанный на группировке заказов на продажу по тегам товаров, входящих в их состав.
Пошаговая реализация
Мы расширим модель sale.order , чтобы группировать заказы на продажу по тегам товаров из строк заказа. Предположим, у нас есть пользовательский модуль с именем sale_tag_grouping.
Шаг 1: Определение вычисляемого поля (Python)
В вашем пользовательском модуле (например, sale_tag_grouping ) расширьте модель sale.order и вычислите поле на основе тегов товаров.
from odoo import models, fields, api
class SaleOrder(models.Model):
_inherit = 'sale.order'
product_tags = fields.Char(
string='Product Tags',
compute='_compute_product_tags',
store=True
)
@api.depends('order_line.product_id.product_tag_ids.name')
def _compute_product_tags(self):
for order in self:
tags = set()
for line in order.order_line:
tags.update(line.product_id.product_tag_ids.mapped('name'))
order.product_tags = ', '.join(sorted(tags)) if tags else ''
Как это работает
- product_tag_ids — это поле M2M в описании товара.
- Функция `set()` в Python гарантирует отсутствие дубликатов.
- Сортировка имен обеспечивает согласованность выходных данных (полезно для группировки).
- Пустая строка позволяет избежать нулевых значений и обеспечивает аккуратность фильтров пользовательского интерфейса.
Поскольку поле хранится в памяти , оно становится настоящим столбцом базы данных, что является ключевым требованием для корректной работы функции группировки (Group By).
Шаг 2: Обновите представление поиска (XML)
В файле представлений (например, views/sale_order_views.xml ) унаследуйте базовое представление поиска и добавьте фильтр для группировки.
Далее расширьте область поиска по заказам на продажу.
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="view_sales_order_filter_inherit" model="ir.ui.view">
<field name="name">sale.order.search.inherit.tag.grouping</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" position="inside">
<separator/>
<filter name="product_tags"
string="Group by Product Tags"
domain="[]"
context="{'group_by': 'product_tags'}"/>
<separator/>
</xpath>
</field>
</record>
</odoo>
- Объяснение :
- context="{'group_by': 'product_tags'}" указывает Odoo на необходимость группировки по вычисляемому полю.
- Пустой домен означает, что дополнительная фильтрация не применяется.
После загрузки раздел « Теги товаров » появится в панели поиска заказов в разделе « Группировка по» > «Пользовательская группа».

После определения XML-представления перейдите в пользовательский интерфейс Odoo и обновите модуль, чтобы применить изменения. Это добавит поле tag_names в форму и включит группировку по тегам.

Шаг 3: (Необязательно) Отобразите поле в форме/древовидном представлении.
Если вы хотите, чтобы пользователи видели вычисленные теги напрямую:
<record id="view_order_form_inherit" model="ir.ui.view">
<field name="name">sale.order.form.inherit.tag.grouping</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='partner_id']" position="after">
<field name="product_tags" readonly="1"/>
</xpath>
</field>
</record>
Шаг 4 — Обновите модуль и протестируйте.
- Добавьте импорты в файл __init__.py.
- Добавьте ваши XML-файлы в файл __manifest__.py.
- Обновите модуль через меню «Приложения».
- Откройте раздел «Продажи» > «Заказы» .
- Используйте Поиск > Группировка по > Теги товаров.
Теперь вы должны увидеть заказы, сгруппированные на основе объединенных товарных тегов, найденных в строках заказа.

В Odoo невозможно группировать данные по полям M2M напрямую, поскольку они не хранятся в таблице модели. Создав хранимое вычисляемое поле, представляющее содержимое M2M, вы можете использовать встроенные механизмы группировки Odoo без проблем с производительностью. Этот подход универсален — его можно применять к тегам, категориям или пользователям в различных модулях, таких как CRM, управление запасами или управление персоналом.