Домены

Содержание

Подготовка

Для того, чтобы использовать следующий пример, вам необходимо переключить текущий разрабатываемый проект на другую ветку.

Вот ее имя - 16.0-domains

Затем удалите текущую базу и создайте новую.

Убедитесь, что у вас не осталось вкладок со старыми сессиями

В файл конфигурации в параметры init_modules и update_modules добавьте имя модуля domains

Запустите менеджер с параметрами -d, -i, и -u

Перейдите откройте браузер по адресу http://127.0.0.1:8069

Что такое домен?

Если мы обратимся к документации, то мы увидим, что она не менялась в этой части довольно долго, вы можете сравнить мой перевод еще 13 версии с текущим вариантом для 17 версии. И увидите, что разнице нет никакой. И этой информации для новичков бывает недостаточно чтобы понять что это такое и как это знание правильно применять на практике.

Домен - это своего рода "фильтр", который состоит из комбинации триплетов и операторов объединенных в единый список. Данный фильтр применяется к некоторому набору записей(или записям в таблице) и если эти записи удовлетворяют условию, содержащемуся в домене, то они проходят фильтр, остальные записи отбрасываются или не учитываются. Каждый триплет является списком или кортежем состоит из трех элементов:

  1. Имя поля - имеет тип строка
  2. Оператор - имеет тип строка
  3. Значение

Простейший пример:

domain = [("field_name", "=", some_value)]
domain = [("name", "=", "Deco Addict")]

В этом примере мы сравниваем значение поля name с текстовым значение "Deco Addict". И если, например, в модели res.partner у нас будут записи, у которых соблюдается это условие, то они пройдут фильтр и попадут в выборку, с которой мы в дальнейшем сможем проводить какие-либо манипуляции

Про все доступные операторы вы можете узнать из документации, ссылки на которую я указал выше.

Так же хотелось бы сделать акцент на операторах, которые объединяют триплеты домена. Читая документацию вы сможете встретить такой терми как arity, переведя его вы узнаете что есть такое слово арность. Если вы не математик по образованию, то вполне возможно что вам это будет совсем не понятно. На самом деле это умное слово всего лишь означает область действия. В данном случае оператор, если имеет арность равной двум, то применяется к двум триплетам следующим за ним. Если арность равна единице, то к одному триплету. Давайте детально разберем пример из документации:

domain = [
1.    ('name','=','ABC'),
2.    ('language.code','!=','en_US'),
3.    '|',
3.1      ('country_id.code','=','be'),
3.2      ('country_id.code','=','de')
]

Этот домен можно прочитать как:

  1. Имя равно "ABC" И
  2. Код языка НЕ равен "en_US" И
  3. Код страны равен "be" ИЛИ "de"

Т.е. оператор | имеет арность 2, соответственно оператор ИЛИ применяется к двум следующим за ним триплетам, а вся конструкция рассматривается как единый элемент. Т.е. если нам нужно выбрать из трех кодов стран, то написание конструкции будет следующим:

domain = [
1.  ('name','=','ABC'),
2.  ('language.code','!=','en_US'),
3.  '|'
3.1 - 4.  '|',
3.1 - 4.1    ('country_id.code','=','be'),
3.1 - 4.2    ('country_id.code','=','de'),
3.2      ('country_id.code','=','by')
]

Этот домен можно прочитать как:

  1. Имя равно "ABC" И
  2. Код языка НЕ равен "en_US" И
  3. Код страны равен "be" ИЛИ
  4. "be" ИЛИ "de"

Применение на практике

Одно из самых частых применений доменов относится к ограничению выборки в полях типа many2many. Оно имеет ряд особенностей, на которых стоит остановится подробнее: Применение доменов в many2one поле

  1. Домен объявляется как атрибут поля при объявлении модели и представляет собой список кортежей на python
  2. Домен объявляется как атрибут поля при объявлении модели и представляет собой строку
  3. Домен объявляется как атрибут поля при объявлении модели и представляет собой вызов лямбда функции, которая будет вызвана и вычислена в момент создания экземпляра класса модели или рекордсета
  4. Домен объявляется как атрибут поля в самом представлении

Выше вы можете видеть 4 способа создать и записать один и тот же домен. Давайте попробуем разобраться в этих тонкостях: В случаях 1 - 3, доме создается с помощью python. Что дает позволяет применять домен ко всем представлениям, которые будут отображать текущую модель. Плюс в случае 3 мы можем собрать домен при попытке прочитать данные записи, что дает большую гибкость нежели просто заранее указанный домен. В случае 4 домен применяется только в конкретном представлении, а уже в других его может не существовать или он может быть другим.

Еще одним не маловажным момент является факт того, что домен считывается в момент создания экземпляра модели, который отображается на форме и подгружается на js клиент и выполняется уже им. Т.е. вы должны понимать создавая домен что он нужен не серверной части, а на клиенте

Это приводит нас к тому, что использование доменов, которые, применяются на стороне клиента позволяет вносить неплохую интерактивность форм, когда предполагаемые значения одного поля зависят от другого:

Значение домена зависит от значения поля

  1. Выбран контакт, у которого есть дочерние контакты (компания и сотруники)
  2. Домен в представлении берет в качестве значения имя поля из п. 1. И таким образом, при выборе организации в другом поле мы уже можем выбрать только ее сотрудников.

Т.е. мы можем использовать значения полей на стороне клиента в качестве значения для домена, обеспечивая таким образом необходимую интерактивность системы.

Так же бывают случаи, когда нам нужен весьма сложный домен, при этом, мы не знаем за ранее всех условий и не имеем возможности создать его конкретно именно в момент обращения к записи или записям. Для этого у каждой модели существует служебный метод _name_search. И переопределив его в целевой модели, на которую ссылается в параметре comodel_name наше поле many2one мы можем добиться еще большей гибкости:

Использование _name_search

  1. Переопределяем метод _name_search в модели res.partner т.к. именно она у нас объявлена в параметре comodel_name нашего many2one поля
  2. Обратите внимение, что у нас в представлении уже объявлен домен и он передается в качестве параметра args
  3. Выводим его в консоль для более наглядного примера
  4. с помощью контекста даем понять, в каких случаях нам необходимо применять наш домен. Это необходимо для того, чтобы отсечь все остальные обращения к данном методу из других мест, т.к. мы переопределяем поведение метода такого глобального бизнес-объекта как res.partner и количество полей many2one со ссылкой на него во всей системе будет измеряться сотнями если не тысячами
  5. добавляем к уже существующему домену наш, который мы хотим создать в текущих условиях. Обратите внимание на инструмент expression, который предназначен для работы с доменами
  6. Мы можем увидеть итоговый домен в консоли перед его применением
  7. Результат работы нашего домена

Если вы будете экспериментировать дальше, то увидите что этот метод вызывается каждый раз при добавлении очередного символа, т.е. как мы видим мы можем создать домен произвольной сложности, который зависит как от текущего состояния записи, так и от любого другого объекта в системе.

Так же домены постоянно применяются при использовании метода search и являются его обязательным аргументом. Ниже вы можете увидеть пример использования:

Использование search

  1. Нажимаем кнопку
  2. Вызывается функция связанная с этой кнопкой
  3. Внутри функции мы полю one_partner_id присваиваем значение равное рекордсету, который получим при использовании метода search и указанного домена
  4. Результат присвоения мы можем видеть на экране.

Метод search возвращает рекордсет из всех записей модели к которой применяется, которые прошли фильтр указанного домена. В нашем случае, если бы контактов с именем Deco Addict было больше, то система бы вернула исключение, т.к. мы не можем присвоить полю типа many2one рекордсет из более чем одной записи.

Разумеется это не все кейсы использования доменов. Я привел самые часто используемые или неочевидные. Как правило в остальных случаях домен используется как фильтр для отбора записей для различных манипуляций.

Обсуждение

Обсудить, указать на ошибки и опечатки можно здесь