ORM API

Модуль реляционного отображения объектов:
  • Иерархическая структура
  • Ограничения согласованности и проверки
  • Метаданные объекта зависят от его статуса
  • Оптимизированная обработка сложного запроса (несколько действий одновременно)
  • Значения полей по умолчанию
  • Оптимизация разрешений
  • Персистенс объект: БД postgresql
  • Конвертация данных
  • Многоуровневая система кэширования
  • Два разных механизма наследования
  • Богатый набор типов полей:
    • классические(varchar, integer, boolean, …)
    • реляционные (one2many, many2one, many2many)
    • функциональные

Модели

Поля модели определяются как ее атрибуты:

from odoo import models, fields
class AModel(models.Model):
    _name = 'a.model.name'

    field1 = fields.Char()

По умолчанию метка поля (видимое пользователем имя) является версией имени поля написанной с большой буквы, и может быть переопределена с помощью параметра string:

field2 = fields.Integer(string="Field Label")

Для различных типов полей и их параметрах смотрите Поля.

Значения по умолчанию определяются как параметры полей с присвоенными им значениями:

name = fields.Char(default="a value")

or as a function called to compute the default value, which should return that value:

def _default_name(self):
    return self.get_value()

name = fields.Char(default=lambda self: self._default_name())

API

class odoo.models.BaseModel[исходный код]

Базовые классы для моделей Odoo.

Модели Odoo создаются наследованием от этого класса:

  • Model для обычных моделей с сохранением состояния в базе данных
  • TransientModel для временных данных, хранящихся в базе данных, но автоматически удаляемых время от времени, с помощью vacuum
  • AbstractModel для абстрактных суперклассов, предназначенных для совместного использования несколькими дочерними моделями

Система автоматически создает экземпляр каждой модели один раз для каждой базы данных. Эти экземпляры представляют доступ к моделям и зависят от того, какие модули установлены в каждой базе данных. По факту класс каждого экземпляра создается из классов Python, которые создаются и наследуются от соответствующей модели.

Каждый экземпляр модели представляет собой «набор записей», то есть упорядоченную коллекцию записей модели. Наборы записей возвращаются такими методами, как browse(), search() или доступом к полям. Записи не имеют явного представления: запись представляется как набор записей из одной записи.

Чтобы создать класс, экземпляр которого не нужно создавать, можно присвоить значение False атрибуту _register.

_auto = False

Отвечает за то, будет ли создана таблица в базе данных (значение по умолчанию: True). Если установлено значение False, переопределите init() для того, чтобы создать таблицу.

_table = None

SQL имя таблицы, которое используется моделью если установлен атрибут _auto

_sequence = None

SQL последовательность используемая для поля ID

_sql_constraints = []

SQL ограничения [(name, sql_def, message)]

_register = True

невидимая в реестре ORM

_name = None

имя модели, (в dot-нотации в пространстве имен модуля)

_description = None

Менее строгое имя модели (краткое описание)

_inherit = None

Python-inherited модели:

Type
str или list(str)
_inherits = {}

представляет собой словарь {„parent_model“: „m2o_field“}, сопоставляющий атрибут _name родительских моделей с именами соответствующих полей:

_inherits = {
    'a.model': 'a_field_id',
    'b.model': 'b_field_id'
}

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

_rec_name = None

поле для описания записи,по умолчанию берется значение атрибута: name

_order = 'id'

поле по которому будет осуществляться сортировка результатов работы метода search() и схожих по функционалу

_check_company_auto = False

Применяется при изменении и создании записей, вызов метода _check_company позволяет убедиться в том, что поле имеет атрибут check_company=True.

_parent_name = 'parent_id'

many2one поле - используется как родительское поле

_parent_store = False

если имеет значение True то вычисляет parent_path поле.

Наряду с полем parent_path field, устанавливается индексируемое хранилище древовидной структуры записей, для того, чтобы можно было быстрее обрабатывать иерархические запросы записей текущей модели используя операторы домена child_of и parent_of.

_abstract = True

определяет является ли модель абстрактной

_transient = False

определяет является ли модель временной

_date_name = 'date'

поле используемое для представления календаря, по умолчанию

_fold_name = 'fold'

поле для определения свернутых групп в представлениях канбан

Абстрактная модель (AbstractModel)

odoo.models.AbstractModel[исходный код]

псевдоним класса odoo.models.BaseModel

Стандартная модель (Model)

class odoo.models.Model[исходный код]

Основной супер-класс для стандартных моделей Odoo, работающих с базой данных.

Модели Одоо создаются наследованием от этого класса:

class user(Model):
    ...

Позже система создаст экземпляр класса один раз для каждой базы данных (для которой установлен модуль, в котором объявлена модель).

Временная модель (TransientModel)

class odoo.models.TransientModel[исходный код]

Модель супер-класс для временных записей, которые создаются на некоторый срок а потом удаляются с помощью vacuum.

Модель TransientModel имеет упрощенное управление правами доступа, все пользователи могут создавать новые записи и могут иметь доступ только к тем записям, которые они создали. Суперпользователь имеет неограниченный доступ ко всем записям TransientModel.

Поля

class odoo.fields.Field[исходный код]

Дескриптор поля содержит определение поля и управляет доступом и присвоением соответствующего поля для записей. При инициализации поля могут быть предоставлены следующие атрибуты:

Параметры
  • string (str) – Метка поля, видимая пользователями (строка); Если не установлено, ORM берет значение поля name , которое определено в данном классе (с заглавной буквы).
  • help (str) – Всплывающая подсказка, видимая пользователями, при наведении курсора на соотвествующее поле
  • readonly (bool) – определяет является ли поле только для чтения (по умолчанию: False) Это влияет только на пользовательский интерфейс. Любое изменение значения поля в коде будет работать (если поле имеет атрибут stored или inversable ).
  • required (bool) – определят является ли заполнение значения поля обязательным ( по умолчанию False)
  • index (bool) – определяет будет ли поле индексироваться в базе данных (по умолчанию False)
  • default (value or callable) – Значение поля по умолчанию; может быть заранее определенным значением, либо быть результатом работы функции, которая принимает в качестве аргумента набор записей и возвращающая значение; используйте default=None, чтобы сбросить значения по умолчанию для поля
  • states (dict) – Словарь отражающий значения состояний в виде списка пар ключ-значение на пользовательском интерфейсе; Возможные атрибуты: readonly, required, invisible. Примечание. Любое значение на основе состояния требует, чтобы в пользовательском интерфейсе на стороне клиента было доступно значение поля state. Обычно это делается путем включения его в соответствующие представления, возможно сделанные невидимыми, если мы не хотим показывать их пользователю.
  • groups (str) – список разделенных запятыми xml-идентификаторов (строка); ограничивает доступ к полям только для пользователей указанных групп
  • company_dependent (bool) – определяет зависит ли значение поля от текущей компании; Значение не сохраняется в таблице модели. Оно зарегистрировано в мета модели ir.property. Когда необходимо значение поля company_dependent, выполняется поиск в записи в модели ir.property, которая связана с текущей компанией (и текущей записью, если такое свойство существует). Если значение изменяется в записи, оно либо изменяет существующее свойство для текущей записи (если оно существует), либо создает новое для текущей компании и res_id. Если значение будет изменено на стороне компании, это повлияет на все записи, для которых значение не было изменено.
  • copy (bool) – определяет следует ли копировать значение поля при дублировании записи (по умолчанию: True для обычных полей, False для полей типа one2many и вычисляемых полей, включая поля свойств и реляционные поля)
  • store (bool) – определяет хранится ли значение поля в базе данных (по умолчанию True, False для вычисляемых полей)
  • group_operator (str) –

    агрегатная функция read_group() используемая при группировке по этому полю.

    Поддерживаются следующие агрегатные функции:

    • array_agg : значения, включая null, объединенные в массив
    • count : количество строк
    • count_distinct : количество отдельных строк
    • bool_and : true если все значения true, иначе false
    • bool_or : true если хотя бы одно значение true, иначе false
    • max : максимальное значение всех приведенных значений
    • min : минимальное значение из всех приведенных значений
    • avg : среднее (среднее арифметическое) всех приведенных значений
    • sum : сумма всех значений
  • group_expand (str) –

    функция, используемая для расширения результатов read_group при группировании по текущему полю.

    @api.model
    def _read_group_selection_field(self, values, domain, order):
        return ['choice1', 'choice2', ...] # available selection choices.
    
    @api.model
    def _read_group_many2one_field(self, records, domain, order):
        return records + self.search([custom_domain])
    

Вычисляемые поля

Параметры
  • compute (str) –

    Имя метода, который вычисляет значение поля

  • compute_sudo (bool) – определяет должно ли поле быть вычислено от имени суперпользователя для обхода прав доступа (по умолчанию True для полей с установленным атрибутом stored, False без оного)
  • inverse (str) – имя метода, который делает обратные вычисления (необязательный атрибут)
  • search (str) – имя метода, реализующего поиск по полю (необязательный атрибут)
  • related (str) –

    последовательность имен полей

Базовые поля (Basic Fields)

class odoo.fields.Boolean[исходный код]

Инкапсулирует класс bool.

class odoo.fields.Char[исходный код]

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

Параметры
  • size (int) – максимальный размер значений, хранящихся для этого поля
  • trim (bool) – определяет будет ли значение принудительно обрезано (по умолчанию, True). Обратите внимание что операция trim применяется только на стороне веб клиента.
  • translate (bool or callable) – включает перевод значений поля; используйте translate = True для перевода значений полей в целом; translate также может быть функцией имеющий следующий вид translate(callback, value) где осуществляет перевод value используя callback(term), чтобы получить перевод терминов.
class odoo.fields.Float[исходный код]

Икапсулирует класс float.

количество знаков после запятой задается атрибутом digits (необязательный атрибут).

Параметры
digits (tuple(int,int) or str) – пара (целое значение, десятичное значение) или строковое значение класса DecimalPrecision.
class odoo.fields.Integer[исходный код]

Инкапсулирует класс int.

Расширенные поля (Advanced Fields)

class odoo.fields.Binary[исходный код]

Инкапсулирует двоичный контент (например файл).

Параметры
attachment (bool) – определяет будет ли значения поля хранится как ir_attachment или как колонка в таблице модели (по умолчанию: True).
class odoo.fields.Html[исходный код]

Инкапсулирует хранение кода html code.

Параметры
  • sanitize (bool) – определяет должно ли значение проходить обработку (по умолчанию: True)
  • sanitize_tags (bool) – определяет нужно ли очищать ли теги (допускается только белый список атрибутов, по умолчанию: True)
  • sanitize_attributes (bool) – определяет нужно ли очищать ли атрибуты (допускается только белый список атрибутов, по умолчанию: True)
  • sanitize_style (bool) – определяет должны ли очищаться атрибуты стилей (по умолчанию: True)
  • strip_style (bool) – следует ли удалять атрибуты стилей (удалены и, следовательно, не очищены, по умолчанию: False)
  • strip_classes (bool) – определяет должны ли удаляться атрибуты классов (по умолчанию: False)
class odoo.fields.Image[исходный код]

Инкапсулирует изображение, расширяя класс Binary.

Параметры
  • max_width (int) – максимальная ширина изображения
  • max_height (int) – максимальная высота изображения
  • verify_resolution (bool) – следует ли проверять разрешение изображения, чтобы оно не превышало максимальное разрешение (по умолчанию: True). Смотрите класс odoo.tools.image.ImageProcess для установки максимального разрешения (по умолчанию: 45e6).
class odoo.fields.Monetary[исходный код]

Инкапсулирует класс float выраженный в виде класса res_currency.

Десятичная точность и символ валюты берутся из атрибута currency_field.

Параметры
currency_field (str) – имя поля Many2one содержащего res_currency валютное поле (default: currency_id)
class odoo.fields.Selection[исходный код]

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

Параметры
  • selection (list(tuple(str,str)) or callable or str) – указывает возможные значения для этого поля. параметр задается либо как список пар (value, label), либо как метод модели, либо как имя метода.
  • selection_add (list(tuple(str,str))) –

    обеспечивает расширение выбора в случае переопределенного поля. Это список пар (value, label) или единичных значений (value,), где единичные значения должны быть переопределенным селектором. Новые значения вставляются в порядке, который соответствует переопределенному селектору и этому списку.:

    selection = [('a', 'A'), ('b', 'B')]
    selection_add = [('c', 'C'), ('b',)]
    > result = [('a', 'A'), ('c', 'C'), ('b', 'B')]
    

Атрибут selection является обязательным, за исключением случаев related или расширенных полей.

class odoo.fields.Text[исходный код]

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

Параметры
translate (bool or callable) – включает перевод значений поля; используйте translate = True для перевода значений полей в целом; translate также может быть функцией имеющий следующий вид translate(callback, value) где осуществляет перевод value используя callback(term), чтобы получить перевод терминов.

Поля времени и даты (Date(time) Fields)

Dates и Datetimes очень важные поля в любом виде бизнес приложений. Их неправильное использование может привести к появлению невидимых, но болезненных ошибок. Этот раздел призван предоставить разработчикам Odoo знания, необходимые для того, чтобы избежать неправильного использования этих полей.

При присвоении значения полям Date/Datetime допустимы следующие параметры:

  • date или datetime объект.
  • Строка следующего формата:

    • YYYY-MM-DD для Date полей,
    • YYYY-MM-DD HH:MM:SS для Datetime полей.
  • False или None.

Класс полей Date и Datetime имеет вспомогательные методы для преобразования объектов в совместимый тип:

лучшие практики для сравнения Date / Datetime:

  • Date поля могут сравниваться только с объектами date.
  • Datetime поля могут сравниваться только с объектами datetime.

Стандартные операции с датами и временем, такие как сложение, вычитание или выборка начала/конца периода, доступны через Date и Datetime. Эти вспомогательные функции также доступны с помощью импорта odoo.tools.date_utils.

class odoo.fields.Date[исходный код]

Инкапсулирует объект python класса date.

static add(value, *args, **kwargs)[исходный код]

Возвращает сумму value и relativedelta.

Параметры
  • value – инициирует date или datetime.
  • args – позиционные аргументы для передачи непосредственно в relativedelta.
  • kwargs – ключевые аргументы для передачи непосредственно в relativedelta.
Результат
итоговое значение date/datetime.
static context_today(record, timestamp=None)[исходный код]

Возвращает текущую дату в часовом поясе клиента в формате, соответствующем date полям.

Параметры
  • record – набор записей, из которого будет получен часовой пояс.
  • timestamp (datetime) – необязательное значение datetime, используемое вместо текущей даты и времени (должно быть datetime, обычные даты нельзя конвертировать между часовыми поясами).
Тип результата
date
static end_of(value, granularity)[исходный код]

Получает окончание временного периода от date или datetime.

Параметры
  • value – инициирует date или datetime.
  • granularity – Тип периода в строковом виде, может быть год, квартал, месяц, неделя, день или час.
Результат
Объект date/datetime соответствующий началу указанного периода.
static start_of(value, granularity)[исходный код]

Получает окончание временного периода от date или datetime.

Параметры
  • value – инициирует date или datetime.
  • granularity – тип периода в строковом виде, может быть год, квартал, месяц, неделя, день или час.
Результат
объект date/datetime соответствующий началу указанного периода.
static subtract(value, *args, **kwargs)[исходный код]

Возвращает разницу между value и relativedelta.

Параметры
  • value – инициирует date или datetime.
  • args – позиционные аргументы для передачи непосредственно в relativedelta.
  • kwargs – ключевые аргументы для передачи непосредственно в relativedelta.
Результат
итоговое значение date/datetime.
static to_date(value)[исходный код]

Преобразует значение value в объект date.

Параметры
value (str or date or datetime) – значение для преобразования.
Результат
объект, представляющий value.
Тип результата
date or None
static to_string(value)[исходный код]

Преобразует date или datetime объект в строку.

Параметры
value – значение для преобразования.
Результат
строка предоставляющая value в формате date , если value имеет тип datetime,то часы, минуты, секунды, tzinfo будут проигнорированы.
Тип результата
static today(*args)[исходный код]

Возвращает текущий день в формате, ожидаемом ORM.

class odoo.fields.Datetime[исходный код]

Инкапсулирует объект python класса datetime.

static add(value, *args, **kwargs)[исходный код]

Возвращает сумму value и relativedelta.

Параметры
  • value – инициирует date или datetime.
  • args – позиционные аргументы для передачи непосредственно в relativedelta.
  • kwargs – ключевые аргументы для передачи непосредственно в relativedelta.
Результат
итоговое значение date/datetime.
static context_timestamp(record, timestamp)[исходный код]

Возвращает указанный timestamp, преобразованный в часовой пояс клиента.

Параметры
  • record – набор записей, из которого будет получен часовой пояс.
  • timestamp (datetime) – значение datetime (выраженное в формате UTC), которое должно быть преобразовано в часовой пояс клиента.
Результат
timestamp , преобразованная в datetime с учетом часового пояса.
Тип результата
datetime
static end_of(value, granularity)[исходный код]

Получает окончание временного периода от date или datetime.

Параметры
  • value – инициирует date или datetime.
  • granularity – Тип периода в строковом виде, может быть год, квартал, месяц, неделя, день или час.
Результат
Объект date/datetime соответствующий началу указанного периода.
static now(*args)[исходный код]

Возвращает текущий день и время в формате, ожидаемом ORM.

static start_of(value, granularity)[исходный код]

Получает окончание временного периода от date или datetime.

Параметры
  • value – инициирует date или datetime.
  • granularity – тип периода в строковом виде, может быть год, квартал, месяц, неделя, день или час.
Результат
объект date/datetime соответствующий началу указанного периода.
static subtract(value, *args, **kwargs)[исходный код]

Возвращает разницу между value и relativedelta.

Параметры
  • value – инициирует date или datetime.
  • args – позиционные аргументы для передачи непосредственно в relativedelta.
  • kwargs – ключевые аргументы для передачи непосредственно в relativedelta.
Результат
итоговое значение date/datetime.
static to_datetime(value)[исходный код]

Преобразует ORM value в значение datetime.

Параметры
value (str or date or datetime) – значение для преобразования.
Результат
объект, представляющий value.
Тип результата
datetime or None
static to_string(value)[исходный код]

Преобразует объект datetime или date в строку.

Параметры
value (datetime or date) – значение для преобразования.
Результат
строка, представляющая value в формате datetime, если ``value``является date, то значение времени будет установлено как полночь (00:00:00).
Тип результата
static today(*args)[исходный код]

Возвращает текущий день, со значение времени в полночь (00:00:00).

Реляционные поля (Relational Fields)

class odoo.fields.Many2one[исходный код]

Значение такого поля - это набор записей размера 0 (нет записи) или 1 (одна запись).

Параметры
  • comodel_name (str) – имя целевой модели Обязательный атрибут за исключением связанных или расширенных полей.
  • domain – необязательный параметр - домен для установки значений кандидатов на стороне клиента (домен или строка)
  • context (dict) – необязательный параметр - контекст для использования на стороне клиента при обработке этого поля
  • ondelete (str) – определяет что делать, если запись, на которую ссылается удалена; возможные значения: 'set null', 'restrict', 'cascade'
  • auto_join (bool) – определяет генерируются ли JOIN при поиске в этом поле (по умолчанию: False)
  • delegate (bool) – установите его в True, чтобы сделать поля целевой модели доступными из текущей модели (соответствует _inherits)
  • check_company (bool) – помечает поле для проверки методом _check_company(). Добавляет домен компании по умолчанию в зависимости от атрибутов поля.
class odoo.fields.One2many[исходный код]

Поле One2many; значение такого поля является набором записей всех записей в comodel_name, так таким образом поле inverse_name было равно текущей записи.

Параметры
  • comodel_name (str) – имя целевой модели
  • inverse_name (str) – имя поля которое имеет обратную связь Many2one в `` comodel_name``
  • domain – необязательный параметр - домен для установки значений кандидатов на стороне клиента (домен или строка)
  • context (dict) – необязательный параметр - контекст для использования на стороне клиента при обработке этого поля
  • auto_join (bool) – определяет генерируются ли JOIN при поиске в этом поле (по умолчанию: False)
  • limit (int) – необязательный параметр - ограничение для использования при чтении записей из comodel_name

Атрибуты comodel_name и inverse_name обязательны, за исключением реляционных полей или расширений для полей.

class odoo.fields.Many2many[исходный код]

Поле Many2many; Значением такого поля является набор записей.

Параметры
  • comodel_name – имя целевой модели (строка) обязательно, за исключением случаев связанных или расширенных полей
  • relation (str) – необязательный парметр - имя таблицы, в которой хранится отношение в базе данных, так называемая развязочная таблица
  • column1 (str) – необязательный параметр - имя столбца, ссылающееся на «эти» записи в таблице relation
  • column2 (str) – необязательный параметр - имя столбца, ссылающегося на «те» записи в таблице relation

Атрибуты relation, column1 и column2 являются необязательными. Если они не указаны, имена автоматически генерируются из имен моделей, если именя model_name и comodel_name отличаются!

Обратите внимание, что наличие нескольких полей с неявными параметрами отношения в данной модели с одним и тем же comodel не принимается ORM, поскольку эти поля будут использовать одну и ту же таблицу. ORM не позволяет двум many2many полям использовать одни и те же параметры отношения, кроме случаев, когда

  • оба поля используют одну и те же model, comodel и relation параметры объявлены явно; или
  • по крайней мере одно поле принадлежит модели с _auto = False.
Параметры
  • domain – необязательный параметр - домен для установки значений кандидатов на стороне клиента (домен или строка)
  • context (dict) – необязательный параметр - контекст для использования на стороне клиента при обработке этого поля
  • check_company (bool) – помечает поле для проверки методом _check_company(). Добавляет домен компании по умолчанию в зависимости от атрибутов поля.
  • limit (int) – необязательный параметр - ограничение для использования при чтении записей из comodel_name

Псевдо-реляционные поля (Pseudo-relational fields)

class odoo.fields.Reference[исходный код]

Псевдо-реляционное поле (не содержится в БД).

Значение поля хранится как string в соответствии с шаблоном "res_model.res_id" в базе данных.

class odoo.fields.Many2oneReference[исходный код]

Псевдо-реляционное поле (не содержится в БД).

Значение поля хранится как integer id в базе данных.

В отличие от полей Reference, модель должна быть указана в поле Char, имя которого должно быть указано в атрибуте model_field для текущего поля Many2oneReference.

Параметры
model_field (str) – имя Char где хранится имя модели.

Вычисляемые поля

Значение полей может быть вычислено (вместо того, чтобы брать значения сразу из базы данных) с помощью параметра compute. Вычисленное значения обязано быть присвоено полю. Если используются значения других полей, то должны быть указаны поля, используя depends().

from odoo import api
total = fields.Float(compute='_compute_total')

@api.depends('value', 'tax')
def _compute_total(self):
    for record in self:
        record.total = record.value + record.value * record.tax
  • зависимости могут быть указанны в виде ссылки на поле, путь к которому вы описываете с помощью dot-нотации:

    @api.depends('line_ids.value')
    def _compute_total(self):
        for record in self:
            record.total = sum(line.value for line in record.line_ids)
    
  • вычисляемые поля по умолчанию не сохраняются, их значения вычисляются и возвращаются по запросу. Параметр store = True сохранит их значение в базе данных и автоматически включит поиск.
  • поиск по вычисленному полю можно включить, установив параметр search. Значение - это имя метода, возвращающее Поисковые домены:

    upper_name = field.Char(compute='_compute_upper', search='_search_upper')
    
    def _search_upper(self, operator, value):
        if operator == 'like':
            operator = 'ilike'
        return [('name', operator, value)]
    

    Метод поиска search при обработке доменов перед выполнением фактического поиска по модели. Он должен возвращать домен, эквивалентный условию: field operator value.

  • По умолчанию вычисляемые поля доступны только для чтения. Для разрешения значений setting в вычислимых полях используйте параметр inverse. Это имя функции, задача которой откатить вычисления и установить в соответствующие поля нужные значения:

    document = fields.Char(compute='_get_document', inverse='_set_document')
    
    def _get_document(self):
        for record in self:
            with open(record.get_document_path) as f:
                record.document = f.read()
    def _set_document(self):
        for record in self:
            if not record.document: continue
            with open(record.get_document_path()) as f:
                f.write(record.document)
    
  • значения для нескольких полей могут быть вычислены одновременно одним и тем же методом, просто используйте его во всех полях и присвойте нужные значения для каждого из них:

    discount_value = fields.Float(compute='_apply_discount')
    total = fields.Float(compute='_apply_discount')
    
    @api.depends('value', 'discount')
    def _apply_discount(self):
        for record in self:
            # compute actual discount from discount percentage
            discount = record.value * record.discount
            record.discount_value = discount
            record.total = record.value - discount
    

Системные поля (Automatic fields)

odoo.fields.id

ID field

Если длина текущего набора записей равна 1, то возвращается id записи содержащейся в этом НЗ.

В противном случае вызывается ошибка.

odoo.fields.create_date

имеет тип Datetime

odoo.fields.create_uid

имеет тип Many2one

odoo.fields.write_date

имеет тип Datetime

odoo.fields.write_uid

имеет тип Many2one

Reserved Field names

Несколько имен полей зарезервированы для предопределенных сценариев, которые отличаются от автоматически заполняемых полей. Они должны быть определены в модели данных, когда настраивается желаемое поведение:

odoo.fields.name

значение по умолчанию для _rec_name, используется для отображения записей в контексте, где требуется репрезентативное «наименование».

имеет тип Char

odoo.fields.active

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

имеет тип Boolean

odoo.fields.state

этапы жизненного цикла объекта, используемые атрибутом states в классе fields.

имеет тип Selection

odoo.fields.parent_id

используется для упорядочивания записей в древовидной структуре и позволяет использовать операторы child_of and parent_of в доменах.

имеет тип Many2one

odoo.fields.parent_path

Когда атрибут _parent_store имеет значение True, используется для хранения значения, отражающего древовидную структуру _parent_name, и для оптимизации операторов child_of и parent_of``в доменах.Он должен быть объявлен с помощью ``index=True для правильной работы.

имеет тип Char

odoo.fields.company_id

Имя основного поля, используемого для использования нескольких компаний в Odoo.

Используется :meth:~odoo.models._check_company для проверки согласованности нескольких компаний. Определяет, распределяется ли запись между компаниями (не значение) или доступна только пользователям данной компании.

Many2one :type: res_company

Наборы записей

Взаимодействие с моделями данных и записями осуществляется с помощью Наборов Записей (НЗ) - упорядоченной коллекцией записей той же модели.

Методы, определенные для модели данных, выполняются над НЗ, а их self и представляет собой экземпляр НЗ:

class AModel(models.Model):
    _name = 'a.model'
    def a_method(self):
        # self can be anything between 0 records and all records in the
        # database
        self.do_operation()

Перебор НЗ приведет к созданию новых НЗ состоящих из одной записи (ОЗ), данный механизм можно сравнить с перебором строки Python который формирует строки из одного символа:

def do_operation(self):
    print(self) # => a.model(1, 2, 3, 4, 5)
    for record in self:
        print(record) # => a.model(1), then a.model(2), then a.model(3), ...

Доступ к полям

НЗ предоставляет интерфейс «Active Record»: поля моделей данных могут считываться и записываться непосредственно из записи как ее атрибуты.

Доступ к значениям поля также возможен как к элементу словаря (dict), что более элегантно и безопасно, чем getattr() для динамических имен полей. Установка значения поля запускает обновление базы данных:

>>> record.name
Example Name
>>> record.company_id.name
Company Name
>>> record.name = "Bob"
>>> field = "name"
>>> record[field]
Bob

Доступ к реляционному полю(Many2one, One2many, Many2many) всегда возвращает НЗ, пустой если поле не задано.

Запись кэша и предварительная выборка

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

record.name             # first access reads value from database
record.name             # second access gets value from cache

Чтобы не считывать одно поле из одной записи за раз, Odoo выполняет предварительную выборку записей и полей, следуя некоторым эвристикам, чтобы получить хорошую производительность. Как только поле должно быть прочитано в данной записи, ORM фактически считывает это поле в большем НЗ и сохраняет возвращаемые значения в кэше для последующего использования. Унаследованный НЗ обычно представляет собой НЗ, из которого запись выбирается путем перебора. Более того, все простые хранимые поля (boolean, integer, float, char, text, date, datetime, selection, many2one) извлекаются целиком; Они соответствуют столбцам таблицы модели и эффективно извлекаются в одном запросе.

Рассмотрим следующий пример, где partners - НЗ из 1000 записей. Без предварительной выборки цикл будет выполнять 2000 запросов к базе данных. При предварительной выборке выполняется только один запрос:

for partner in partners:
    print partner.name          # first pass prefetches 'name' and 'lang'
                                # (and other fields) on all 'partners'
    print partner.lang

Предварительная выборка также работает на вторичных записях: при чтении значений реляционных полей (которые являются записями) подписываются на будущую предварительную выборку. При обращении к одной из этих вторичных записей происходит предварительная выборка всех вторичных записей из одной и той же модели данных. В следующем примере генерируются только два запроса: один для партнеров и один для стран:

countries = set()
for partner in partners:
    country = partner.country_id        # first pass prefetches all partners
    countries.add(country.name)         # first pass prefetches all countries

Декораторы методов

Модуль API Odoo определяет окружение Odoo (Odoo Environments) и декораторы методов.

odoo.api.depends(*args)[исходный код]

Возвращает декоратор, который задает зависимости полей для метода «compute» (для вычисляемых полей в новом стиле). Каждый аргумент должен быть строкой, состоящей из разделенных точками последовательностей имен полей:

pname = fields.Char(compute='_compute_pname')

@api.depends('partner_id.name', 'partner_id.is_company')
def _compute_pname(self):
    for record in self:
        if record.partner_id.is_company:
            record.pname = (record.partner_id.name or "").upper()
        else:
            record.pname = record.partner_id.name

В качестве аргумента можно передать одну функцию. В этом случае зависимости задаются вызовом функции внутри модели которой принадлежит поле.

odoo.api.depends_context(*args)[исходный код]

Возвращает декоратор, который задает контекст зависимостей для не сохраняемого метода «compute» (для вычисляемых полей в новом стиле). Каждый аргумент является ключом в словаре контекста:

price = fields.Float(compute='_compute_product_price')

@api.depends_context('pricelist')
def _compute_product_price(self):
    for product in self:
        if product.env.context.get('pricelist'):
            pricelist = self.env['product.pricelist'].browse(product.env.context['pricelist'])
        else:
            pricelist = self.env['product.pricelist'].get_default_pricelist()
        product.price = pricelist.get_products_price(product).get(product.id, 0.0)

Все зависимости должны быть хешируемыми. Следующие ключи имеют специальную поддержку:

  • force_company (значение в контексте или id текущей компании),
  • uid (id текущего пользователя и флаг суперпользователя),
  • active_test (значение в env.context или значение в field.context).
odoo.api.constrains(*args)[исходный код]

Декорирует проверку ограничений.

Каждый аргумент должен быть именем поля, используемым для проверки:

@api.constrains('name', 'description')
def _check_description(self):
    for record in self:
        if record.name == record.description:
            raise ValidationError("Fields name and description must be different")

Вызывается для записей, если в одном из указанных полей было произведено изменение.

Будет вызван класс ValidationError, если проверка не прошла.

odoo.api.onchange(*args)[исходный код]

Возвращает декоратор, чтобы задекорировать метод onchange для заданных полей.

В представлении в виде формы где появляется поле, метод вызывается, когда одно из заданных полей изменяется. Метод вызывается в псевдо-записи, содержащей значения, присутствующие в форме. Назначения полей в этой записи автоматически отправляются обратно клиенту.

Каждый аргумент должен быть именем поля:

@api.onchange('partner_id')
def _onchange_partner(self):
    self.message = "Dear %s" % (self.partner_id.name or "")
return {
    'domain': {'other_id': [('partner_id', '=', partner_id)]},
    'warning': {'title': "Warning", 'message': "What is this?", 'type': 'notification'},
}

Если тип установлен как notification, предупреждение будет отображаться в notification. В противном случае он будет отображаться в диалоговом окне по умолчанию.

odoo.api.returns(model, downgrade=None, upgrade=None)[исходный код]

Возвращает декоратор для методов, возвращающих экземпляры model.

Параметры
  • model – наименование модели данных или 'self' для текущей модели данных
  • downgrade – функция downgrade(self, value, *args, **kwargs) для преобразования нового стиля value в старый
  • upgrade – функция upgrade(self, value, *args, **kwargs) для преобразования из старого стиля value в новый

Аргументы self, *args and **kwargs - это параметры, которые передаются методу в новом стиле.

Декоратор приспосабливает вывод метода к стилю API: id, ids или False для старого стиля и НЗ для нового:

@model
@returns('res.partner')
def find_partner(self, arg):
    ...     # return some record

# output depends on call style: traditional vs record style
partner_id = model.find_partner(cr, uid, arg, context=context)

# recs = model.browse(cr, uid, ids, context)
partner_record = recs.find_partner(arg)

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

Эти декораторы автоматически наследуются: метод, который переопределяет декорированный существующий метод, будет задекорирован тем же @returns(model).

odoo.api.model(method)[исходный код]

Задекорируйте метод в новом стиле, где self - НЗ, но его содержимое не релевантно, только модель данных. Таким способом:

@api.model
def method(self, args):
    ...
odoo.api.model_create_multi(method)[исходный код]

Задекорируйте метод, который берет список словарей и создает несколько записей. Метод может быть вызван либо с одним dict, либо со списком dicts:

record = model.create(vals)
records = model.create([vals, ...])

Окружение (Environment)

Класс Environment хранит различные контекстные данные, используемые ORM: курсор базы данных (для формирования запросов к базе данных), текущий пользователь (для проверки прав доступа) и текущий контекст (хранение произвольных метаданных). В окружении также хранятся кэши.

Все НЗ имеют окружение, доступ к которому можно получить с помощью env и предоставляет доступ к:

  • текущий пользователь (user)
  • курсор (cr)
  • флаг суперпользователя (su)
  • или контекст (context)
>>> records.env
<Environment object ...>
>>> records.env.user
res.user(3)
>>> records.env.cr
<Cursor object ...)

При создании НЗ из другого набора записей окружение наследуется. Окружение может быть использовано для получения пустого НЗ в другой модели данных а так же для формирования запроса к модели:

>>> self.env['res.partner']
res.partner()
>>> self.env['res.partner'].search([['is_company', '=', True], ['customer', '=', True]])
res.partner(7, 18, 12, 14, 17, 19, 8, 31, 26, 16, 13, 20, 30, 22, 29, 15, 23, 28, 74)
Environment.ref(xml_id, raise_if_not_found=True)[исходный код]

Возвращает запись соответствующей xml_id.

Environment.lang

Возвращает код текущего языка.

Тип результата
Environment.user

Возвращает текущего пользователя (как экземпляр).

Тип результата
res_users
Environment.company

Возвращает текущую компанию (как экземпляр).

Если не указана в контексте (allowed_company_ids),то откатывается до значения компании текущего пользователя.

Исключение
AccessError – недопустимое или несанкционированное allowed_company_ids содержимое ключа контекста.
Результат
текущая компания (default= self.user.company_id)
Тип результата
res.company
Environment.companies

Возвращает НЗ компаний к которым у пользователя есть доступ.

если не указано в контексте (allowed_company_ids), откатывается до компаний текущего пользователя.

Исключение
AccessError – недопустимое или несанкционированное allowed_company_ids содержимое ключа контекста.
Результат
текущие компании (default= self.user.company_ids)
Тип результата
res.company

Изменение окружения

Model.with_context([context][, **overrides]) → records[исходный код]

Возвращает новую версию этого набора записей, присоединенного к расширенному контексту.

Расширенный контекст является либо предоставленный context, в котором объеденены overrides, либо текущий контекст, в котором объединены overrides например:

# current context is {'key1': True}
r2 = records.with_context({}, key2=True)
# -> r2._context is {'key2': True}
r2 = records.with_context(key2=True)
# -> r2._context is {'key1': True, 'key2': True}
Model.with_user(user)[исходный код]

Возвращает новую версию этого НЗ, прикрепленную к данному пользователю, в режиме,не-суперпользователем, пока user не станет суперпользователем (по соглашению суперпользователь всегда находится в режиме суперпользователя.)

Model.with_env(env)[исходный код]

Возвращает новую версию этого НЗ, прикрепленного к предоставленному окружению.

Параметры
env (Environment) –
Model.sudo([flag=True])[исходный код]

Возвращает новую версию этого НЗ с включенным или отключенным режимом суперпользователя, в зависимости от flag. Режим суперпользователя не меняет текущего пользователя, а просто обходит проверки прав доступа.

Выполнение SQL запросов

В окружении атрибут cr является курсором для выполнения транзакции в текущей базе данных и позволяет напрямую выполнять SQL запросы, также применяется для запросов, которые трудно выразить с помощью ORM (например, сложные join’ы), либо по причинам производительности:

self.env.cr.execute("some_sql", param1, param2, param3)

Поскольку модели данных используют один и тот же курсор, а класс Environment содержит различные кэши, эти кэшидолжны быть недействительными при изменении базы данных с помощью чистого SQL, или дальнейшее использование моделей может стать некогерентным. Необходимо очищать кэши при использовании CREATE, UPDATE или DELETE в SQL, но не SELECT (который просто читает базу данных).

Model.invalidate_cache(fnames=None, ids=None)[исходный код]

Сделайте недействительными кэши записей после того, как некоторые записи были изменены. В случаях кода fnames и ids имеют значение None, все кэши очищены.

Параметры
  • fnames – список измененных полей,или None для всех полей
  • ids – список id измененных записей, или None для всех

Базовые методы ORM

Create/update

Model.create(vals_list) → records[исходный код]

Создает новые записи для модели.

Новая запись инициализируется с использованием значений из списка словарей vals_list и при необходимости из default_get().

Параметры
vals_list (list) –

значения для полей модели, как список словарей:

[{'field_name': field_value, ...}, ...]

Для обратной совместимости, vals_list может быть словарем. Он обрабатывается как одноэлементный список [vals], и возвращается одна запись.

смотрите write() чтобы узнать детали

Результат
создает записи
Исключение
  • AccessError
    • Если у пользователя нет прав на создание объекта
    • Если пользователь пытается обойти правила доступа для создания на запрошенном объекте
  • ValidationError – Если пользователь пытается ввести недопустимое значение для поля, которое не выбрано
  • UserError – Если в иерархии объектов будет создан цикл в результате операции (такой как установка объекта как собственного родителя)
Model.copy(default=None)[исходный код]

Дублирует запись self, обновляя ее значениями по умолчанию

Параметры
default (dict) – Словарь значений поля для переопределения в исходных значениях скопированной записи, например: {'field_name': overridden_value, ...}
Результат
новая запись
Model.default_get(fields) → default_values[исходный код]

Возвращает значения по умолчанию для полей в fields_list. Значения по умолчанию определяются контекстом, пользовательскими настройками по умолчанию и самой моделью.

Параметры
fields_list – список имен полей
Результат
словарь, где ключ имя поля а значение - его значение по умолчанию, если оно есть.
Model.name_create(name) → record[исходный код]

Создает новую запись, вызвав create(), указав только одно значение: отображаемое имя новой записи.

Новая запись будет инициализироваться с любыми значениями по умолчанию, применимыми к этой модели или предоставляемыми через контекст. Применяется обычное поведение create().

Параметры
name – Отображаемое имя создаваемой записи
Тип результата
tuple
Результат
name_get() значение созданной записи
Model.write(vals)[исходный код]

Обновляет все записи в текущем НЗ с указанными значениями.

Параметры
vals (dict) – поля для обновления и их будущие значения например:: {'foo': 1, 'bar': "Qux"} установит значение поля foo в 1 а поля bar как "Qux" если такое допустимо (в противном случае будет вызвана ошибка).
Исключение
  • AccessError
    • Если у пользователя нет прав на запись для запрашиваемого объекта
    • Если пользователь пытается обойти правила доступа для записи на запрошенном объекте
  • ValidationError – Если пользователь пытается ввести недопустимое значение для поля, которое не выбрано
  • UserError – Если в иерархии объектов будет создан цикл в результате операции (такой как установка объекта как собственного родителя)
  • Для числовых полей (Integer, Float) значение должно быть соответствующего типа
  • Для Boolean, значение должно быть bool
  • Для Selection, значение должно соответствовать значениям выбора (обычно str, иногда int`)
  • Для Many2one, значение должно быть id записи
  • Другие нереляционные поля используют строку для значения

  • One2many и Many2many используют специальный формат «команд» для управления набором записей, хранящихся/связанных с этим полем.

    Этот формат представляет собой список триплетов, выполняемых последовательно, где каждый триплет является командой, выполняемой по набору записей. Не все команды применяются во всех ситуациях. Возможные команды:

    (0, 0, values)
    Добавляет новую запись, созданную из предоставленного value.
    (1, id, values)
    Обновляет существующую запись c id id значениями в values. Нельзя использовать в create().
    (2, id, 0)
    Удаляет запись с id id из НЗ, а затем удаляет его (из базы данных). Нельзя использовать в create().
    (3, id, 0)
    Удаляет запись с id id из НЗ, а затем удаляет его (из базы данных). Нельзя использовать в create().
    (4, id, 0)
    Добавляет существующую запись с id id в НЗ.
    (5, 0, 0)
    Удаляет все записи из НЗ, что эквивалентно использованию команды 3 для каждой записи явно. Нельзя использовать в create().
    (6, 0, ids)
    Заменяет все существующие записи в НЗ списком ids, что эквивалентно использованию команды 5, за которой следует команда 4 для каждого id в ids.
Model.flush(fnames=None, records=None)[исходный код]

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

Search/Read

Model.browse([ids]) → records[исходный код]

Возвращает НЗ для id, предоставленных в качестве параметра в текущей среде.

self.browse([7, 18, 12])
res.partner(7, 18, 12)
Параметры
ids (int or list(int) or None) – id(s)
Результат
Набор записей
Model.search(args[, offset=0][, limit=None][, order=None][, count=False])[исходный код]

Осуществляет поиск записей на базе args домен поиска.

Параметры
  • argsдомен поиска. Используйте пустой список для соответствия всем записям.
  • offset (int) – Количество игнорируемых результатов (по умолчанию: none)
  • limit (int) – Максимальное количество возвращаемых записей (по умолчанию: все)
  • order (str) – Строка сортировки
  • count (bool) – Если True, только подсчитывает и возвращает количество совпадающих записей (по умолчанию: False)
Результат
Не более ``limit` записей, соответствующих критериям поиска
Исключение
AccessError
  • Если пользователь пытается обойти правила доступа для чтения на запрошенном объекте.
Model.search_count(args) → int[исходный код]

Возвращает количество записей в текущей модели и совпадающих с доменом.

Ищет записи, у которых есть отображаемое имя, соответствующее заданному шаблону name, когда совпадает с указанным operator, а также соответствуют необязательной области поиска (args).

Это используется, например, для предоставления предложений, основанных на частичном значении для реляционного поля. Иногда можно рассматривать как обратную функцию name_get(), но это не гарантируется.

Этот метод эквивалентен вызову search() с поисковым доменом на основе display_name, а затем примененному name_get() к результату поиска.

Параметры
  • name (str) – Шаблон имени, с которым нужно сопоставить
  • args (list) – необязательный параметр - домен поиска (см. search() для синтаксиса), указав дальнейшие ограничения
  • operator (str) – оператор домена для сравнения с name, например 'like' или ' = '.
  • limit (int) – необязательный параметр - максимальное количество возвращаемых записей
Тип результата
list
Результат
Список пар (id, text_repr) для всех совпадающих записей.
Model.read([fields])[исходный код]

Читает запрошенные поля для записей в self, низкоуровневом/RPC-методе. В коде Python предпочитайте browse().

Параметры
fields – список имен полей для возврата (по умолчанию все поля)
Результат
список словарей, отображающих имена полей с их значениями, с одним словарем на каждую запись
Исключение
AccessError – Если у пользователя нет прав на чтение некоторых из данных записей
Model.read_group(domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)[исходный код]

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

Параметры
  • domain (list) – домен поиска. Используйте пустой список для соответствия всем записям.
  • fields (list) – список полей, присутствующих в представлении типа список, для указанного объекта . Каждый элемент - это либо 'field' (имя поля с использованием агрегации по умолчанию), либо 'field:agg' (поле агрегирования с функцией агрегирования 'agg'), или 'name:agg(field)' (поле агрегации с 'agg' и возвращаемого как 'name'). Возможные функции агрегирования предоставлены PostgreSQL (https://www.postgresql.org/docs/current/static/functions-aggregate.html) и 'count_distinct', с ожидаемым значением.
  • groupby (list) – Список с описаниями groupby , по которым записи будут сгруппированы. groupby описание представляет собой либо поле (тогда оно будет сгруппировано по этому полю), либо поле 'field: groupby_function' . Прямо сейчас единственными поддерживаемыми функциями являются 'day', 'week', 'month',``“quarter“`` или 'year' и они имеют смысл только для полей date/datetime.
  • offset (int) – необязательный параметр - количество записей для пропуска
  • limit (int) – необязательный параметр - максимальное количество возвращаемых записей
  • orderby (list) – необязательный параметр order by, для переопределения естественного порядка сортировки групп, см. search() (поддерживается только для many2one полей в настоящее время)
  • lazy (bool) – если true, результаты группируются только первым groupby , а остальные groupby помещаются в ключ __context. Если false, все groupby выполняются за один вызов.
Результат
список словарей (один словарь для каждой записи), содержащий: *значения полей, сгруппированных по полям в аргументе groupby * __domain: список кортежей, определяющих критерии поиска * __context: словарь с аргументом типа groupby
Тип результата
[{„field_name_1“: value, ..]
Исключение
AccessError
  • Если пользователь не имеет прав на запрашиваемый объект
  • Если пользователь пытается обойти правила доступа для чтения на запрошенном объекте

Fields/Views

Model.fields_get([fields][, attributes])[исходный код]

Возвращает определение каждого поля.

Возвращаемое значение - словарь (проиндексированный по имени поля) словарей. Включены поля _inherits’d. Атрибуты string, help и selection (если присутствуют) транслируются.

Параметры
  • allfields – список полей для документа, будут выбраны все поля если, значение не присвоено или не указано
  • attributes – список атрибутов описания, возвращаемых для каждого поля, все, если они пусты или не указаны
Model.fields_view_get([view_id | view_type='form'])[исходный код]

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

Параметры
  • view_id (int) – id представления или None
  • view_type (str) – Тип представления, возвращаемого, если view_id равно None („form“, „tree“, …)
  • toolbar (bool) – true для включения контекстных действий
  • submenu – deprecated
Результат
composition of the requested view (including inherited views and extensions)
Тип результата
Исключение
  • AttributeError
    • Если унаследованное представление имеет неизвестную позицию для работы с другими, отличную от 'before', 'after', 'inside', 'replace',
    • Если в родительском представлении обнаружен какой-либо тег, отличный от 'position'
  • Invalid ArchitectureError – Если есть представление, отличное от form, tree, calendar, search и т. д., определенных в структуре

Поисковые домены

Домен - это список критериев, каждый критерий состоит из трех частей ( является либо списком или кортежем) и состоит из (имя_поля, оператор, значние) где:

  • имя_поля (str)
    имя поля текущей модели или отношение через класс Many2one с использованием dot-нотации, например 'street' или 'partner_id.country'
  • operator (str)

    оператор, используемый для сравнения имя_поля со значением. Допустимые операторы:

    =
    равно
    !=
    не равно
    >
    больше чем
    >=
    больше чем или равно
    <
    меньше чем
    <=
    меньше чем или равно
    =?
    не задано или равно (возварщает true если значение является либо``None`` или False, в противном случае ведет себя как =)
    =like
    сопоставляет имя_поля с шаблоном значения. Подчеркивание _ в шаблоне означает (соответствует) любому одиночному символу; знак процента % соответствует любой строке из нуля или более символов.
    like
    сопоставляет имя_поля с шаблоном %значения%. Так же как =like, но оборачивает значение в % перед сравнением
    not like
    не сопоставляет с шаблоном %value%
    ilike
    не чувтсвительный к регистру like
    not ilike
    не чувствительный к регистру not like
    =ilike
    не чувтсвительный к регистру =like
    in
    равно любому из элементов значения, значение должно быть списком элементов
    not in
    не равно любому из элементов значения
    child_of

    дочернее значение (потомок) value записи (значение может быть как одним элементом, либо списком элементов).

    Принимает во внимание семантику модели данных (т. е. за следующим реляционным полем , с наименованием _parent_name).

    parent_of

    является предком (восходящим) value записи (значение может быть как одним элементом, либо списком элементов).

    Принимает во внимание семантику модели данных (т. е. за следующим реляционным полем , с наименованием _parent_name).

  • value
    тип переменной, который должен быть сопоставим (через operator) с указанным полем.

Критерии домена могут быть объединены с помощью логических операторов в виде prefix:

'&'
логическое И, операция по умолчанию для объединения критериев, следующих друг за другом. Арность 2 (использует следующие 2 критерия или комбинации).
'|'
логическое ИЛИ, арность 2.
'!'

Логическое НЕ, арность 1.

Информация об НЗ

Model.ids

Возвращает список актуальных id записей соответствующих self.

odoo.models.env

Возвращает окружение предоставленного НЗ.

Type
Environment
Model.exists() → records[исходный код]

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

if record.exists():
    ...

По соглашению, новые записи возвращаются как существующие.

Model.ensure_one()[исходный код]

Проверяет, что текущий НЗ содержит одну запись. В противном случае возникает исключение.

Исключение
odoo.exceptions.ValueErrorlen(self) != 1
Model.name_get() → [(id, name), ...][исходный код]

Возвращает текстовое представление для записей в self. По умолчанию это значение поля display_name.

Результат
список пар (id, text_repr) для каждой записи
Тип результата
list(tuple)
Model.get_metadata()[исходный код]

Вернуть некоторые метаданные предоставленных записей.

Результат
список словарей владения для каждой запрашиваемой записи
Тип результата

список словарей со следующими ключами:

  • id: object id
  • create_uid: пользователь, который создал запись
  • create_date: дата создания записи
  • write_uid: пользователь, который последним изменил запись
  • write_date: дата последнего изменения записи
  • xmlid: XML ID используемый для ссылки на эту запись (если она есть), в формате module.name
  • noupdate: булево значение говорящее о том будет ли запись изменена или нет

Operations

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

  • record in set возвращает запись (которая должна быть набором из 1 элемента) если таковая присутствует присутствует в НЗ set. record not in set - это обратная операция
  • set1 <= set2 и set1 < set2 возвращает НЗ set1 если он входит НЗ set2 (resp. strict)
  • set1 >= set2 and set1 > set2 возвращает НЗ set1 если он включает в себя НЗ set2 (resp. strict)
  • set1 | set2 возвращает объединение двух НЗ, новый НЗ содержит все записи, имеющиеся каждом источнике
  • set1 & set2 возвращает пересечение двух НЗ, новый НЗ содержит только те записи которые содержатся одновременно в обоих источниках
  • set1 - set2 возвращает новый НЗ, содержащий только записи НЗ set1, которые не входят в НЗ set2

НЗ это итерируемый объект, поэтому обычные инструменты Python доступны для работы с ним (map(), sorted(), ifilter(), …) однако они возвращают либо list или iterator, удаляя возможность вызывать методы для возвращенных результатов, или использовать операции НЗ.

Recordsets therefore provide the following operations returning recordsets themselves (when possible):

Filter

Model.filtered(func)[исходный код]

Возвращает набор записей self, удовлетворяющих func.

Параметры
func (callable or str) – функция или разделенная точками последовательность имен полей
Результат
НЗ удовлетворяющий функции, может быть пустым.
# only keep records whose company is the current user's
records.filtered(lambda r: r.company_id == user.company_id)

# only keep records whose partner is a company
records.filtered("partner_id.is_company")
Model.filtered_domain(domain)[исходный код]

Map

Model.mapped(func)[исходный код]

Применяет func во ко всем записям в self, и возвращает результат в виде списка или НЗ (если func возвращает записи). В последнем случае порядок возвращаемого НЗ произволен.

Параметры
func (callable or str) – функция или разделенная точками последовательность имен полей
Результат
self если функция falsy, результат функции применяется ко всем записям self.
Тип результата
list or recordset
# returns a list of summing two fields for each record in the set
records.mapped(lambda r: r.field1 + r.field2)

The provided function can be a string to get field values:

# returns a list of names
records.mapped('name')

# returns a recordset of partners
records.mapped('partner_id')

# returns the union of all partner banks, with duplicates removed
records.mapped('partner_id.bank_ids')

Sort

Model.sorted(key=None, reverse=False)[исходный код]

Возвращает НЗ self, упорядоченный(отсортированный) по``key``.

Параметры
  • key (callable or str or None) – Либо функцию одного аргумента, которая возвращает ключ сравнения для каждой записи, либо имя поля, либо ` None``, в этом случае записи упорядочиваются в соответствии с порядком сортировки модели по умолчанию
  • reverse (bool) – Если True, возвращает результат в с сортировкой в обратном порядке
# sort records by name
records.sorted(key=lambda r: r.name)

Наследование и расширение

Odoo обеспечивает три различных механизма для расширения моделей данных по модульному принципу:

  • создание новой модели данных из уже существующей, добавляя новую информацию в копию, но оставляя исходный модуль как есть
  • расширение моделей , определенных в других модулях, заменяя предыдущую версию
  • делегировании некоторых полей моделей к записям, которые они содержат

Классическое наследование

При использовании атрибутов _inherit и _name вместе, Odoo создает новую модель, используя уже существующую (с помощью атрибута _inherit) в качестве базиса. Новая модель получает все поля, методы и мета-информацию (defaults & al) от базисной модели.

class Inheritance0(models.Model):
    _name = 'inheritance.0'
    _description = 'Inheritance Zero'

    name = fields.Char()

    def call(self):
        return self.check("model 0")

    def check(self, s):
        return "This is {} record {}".format(s, self.name)

class Inheritance1(models.Model):
    _name = 'inheritance.1'
    _inherit = 'inheritance.0'
    _description = 'Inheritance One'

    def call(self):
        return self.check("model 1")

и их использование:

        a = env['inheritance.0'].create({'name': 'A'})
        b = env['inheritance.1'].create({'name': 'B'})
            a.call()
            b.call()

даст следующий результат:

            "This is model 0 record A"
            "This is model 1 record B"

вторая модель унаследовала от первой метод проверки check и ее поле name, но переопределила метод call, как при использовании стандартного механизма наследования Python.

Расширение

При использовании _inherit, но не учитывая _name, новая модель данных заменит собой уже существующую, расширяя ее. Это полезно для добавления новых полей или методов в существующие модели данных (созданные в других модулях), или их индивидуальной настройки (например, чтобы изменить их порядок сортировки по умолчанию):

class Extension0(models.Model):
    _name = 'extension.0'
    _description = 'Extension zero'

    name = fields.Char(default="A")

class Extension1(models.Model):
    _inherit = 'extension.0'

    description = fields.Char(default="Extended")
        record = env['extension.0'].create({})
        record.read()[0]

даст следующий результат:

        {'name': "A", 'description': "Extended"}

Делегирование

Третий механизм наследования обеспечивает большую гибкость (существует возможность изменения во время выполнения) но требует больше мощностей: используя _inherits модель данных делегирует поиск любого поля, не найденного в текущей модели данных «дочерним» моделям данных. Делегирование осуществляется с помощью Reference, полей автоматически установленных на родительской модели данных.

Основное различие заключается в значении. Когда используется Делегирование, модель has one вместо is one, превращает отношения в композицию вместо наследования:


class Screen(models.Model):
    _name = 'delegation.screen'
    _description = 'Screen'

    size = fields.Float(string='Screen Size in inches')

class Keyboard(models.Model):
    _name = 'delegation.keyboard'
    _description = 'Keyboard'

    layout = fields.Char(string='Layout')

class Laptop(models.Model):
    _name = 'delegation.laptop'
    _description = 'Laptop'

    _inherits = {
        'delegation.screen': 'screen_id',
        'delegation.keyboard': 'keyboard_id',
    }

    name = fields.Char(string='Name')
    maker = fields.Char(string='Maker')

    # a Laptop has a screen
    screen_id = fields.Many2one('delegation.screen', required=True, ondelete="cascade")
    # a Laptop has a keyboard
    keyboard_id = fields.Many2one('delegation.keyboard', required=True, ondelete="cascade")
        record = env['delegation.laptop'].create({
            'screen_id': env['delegation.screen'].create({'size': 13.0}).id,
            'keyboard_id': env['delegation.keyboard'].create({'layout': 'QWERTY'}).id,
        })
            record.size
            record.layout

даст результат:

            13.0
            'QWERTY'

есть возможность сделать запись прямо в делегированное поле:

        record.write({'size': 14.0})

Инкрементальное Определение Полей

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

Например, второй класс ниже только добавляет всплывающую подсказку в поле state

class First(models.Model):
    _name = 'foo'
    state = fields.Selection([...], required=True)

class Second(models.Model):
    _inherit = 'foo'
    state = fields.Selection(help="Blah blah blah")

Управление ошибками

Модуль Odoo Exceptions определяет несколько основных типов исключений.

Эти типы понимаются уровнем RPC. Любой другой тип исключения эскалируется, пока уровень RPC не будет рассматриваться как «Server error».

exception odoo.exceptions.AccessDenied(message='Access denied')[исходный код]

Неверный логин/пароль.

exception odoo.exceptions.AccessError(msg)[исходный код]

Ошибка прав доступа.

exception odoo.exceptions.CacheMiss(record, field)[исходный код]

Недостающие значения в кэше.

exception odoo.exceptions.MissingError(msg)[исходный код]

Пропущенные записи.

exception odoo.exceptions.RedirectWarning[исходный код]

Предупреждение с возможностью перенаправления пользователя вместо простого отображения предупреждающего сообщения.

Параметры
  • action_id (int) – id действия, где выполняется перенаправление
  • button_text (str) – текст, который нужно поместить на кнопку, которая вызовет перенаправление.
exception odoo.exceptions.UserError(msg)[исходный код]

Ошибка, управляемая клиентом.

Обычно, когда пользователь пытается сделать что-то, что не имеет смысла, учитывая текущее состояние записи.

exception odoo.exceptions.ValidationError(msg)[исходный код]

Нарушение ограничений python.