- Модуль реляционного отображения объектов:
- Иерархическая структура
- Ограничения согласованности и проверки
- Метаданные объекта зависят от его статуса
- Оптимизированная обработка сложного запроса (несколько действий одновременно)
- Значения полей по умолчанию
- Оптимизация разрешений
- Персистенс объект: БД 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
для временных данных, хранящихся в базе данных, но автоматически удаляемых время от времени, с помощью vacuumAbstractModel
для абстрактных суперклассов, предназначенных для совместного использования несколькими дочерними моделями
Система автоматически создает экземпляр каждой модели один раз для каждой базы данных. Эти экземпляры представляют доступ к моделям и зависят от того, какие модули установлены в каждой базе данных. По факту класс каждого экземпляра создается из классов Python, которые создаются и наследуются от соответствующей модели.
Каждый экземпляр модели представляет собой «набор записей», то есть упорядоченную коллекцию записей модели. Наборы записей возвращаются такими методами, как browse()
, search()
или доступом к полям. Записи не имеют явного представления: запись представляется как набор записей из одной записи.
Чтобы создать класс, экземпляр которого не нужно создавать, можно присвоить значение False атрибуту _register
.
_auto = False
Отвечает за то, будет ли создана таблица в базе данных (значение по умолчанию: True
). Если установлено значение False
, переопределите init()
для того, чтобы создать таблицу.
Совет
Для того, чтобы создать модель без таблицы в базе, унаследуйте класс AbstractModel
.
_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 модели:
_inherits = {}
представляет собой словарь {„parent_model“: „m2o_field“}, сопоставляющий атрибут _name родительских моделей с именами соответствующих полей:
_inherits = {
'a.model': 'a_field_id',
'b.model': 'b_field_id'
}
реализация композиционного наследования: новая модель предоставляет все поля наследуемой модели, но не хранит ни одного из них: сами значения остаются в связанной записи.
Предупреждение
если несколько полей с одинаковым именем определены в атрибуте _inherits
наследуемых моделей, унаследованное поле будет соответствовать последнему (в порядке очереди, указанной в списке наследования).
_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, иначе falsebool_or
: true если хотя бы одно значение true, иначе falsemax
: максимальное значение всех приведенных значений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
(необязательный атрибут).
class odoo.fields.Integer[исходный код]
Инкапсулирует класс int
.
Расширенные поля (Advanced Fields)
class odoo.fields.Binary[исходный код]
Инкапсулирует двоичный контент (например файл).
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
.
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
, но используется для более длинного содержимого, не имеет размера и обычно отображается как многострочное текстовое поле.
bool
or
callable
) – включает перевод значений поля; используйте translate = True
для перевода значений полей в целом; translate
также может быть функцией имеющий следующий вид translate(callback, value)
где осуществляет перевод value
используя callback(term)
, чтобы получить перевод терминов.Поля времени и даты (Date(time) Fields)
Dates
и Datetimes
очень важные поля в любом виде бизнес приложений. Их неправильное использование может привести к появлению невидимых, но болезненных ошибок. Этот раздел призван предоставить разработчикам Odoo знания, необходимые для того, чтобы избежать неправильного использования этих полей.
При присвоении значения полям Date/Datetime допустимы следующие параметры:
date
илиdatetime
объект.Строка следующего формата:
False
илиNone
.
Класс полей Date и Datetime имеет вспомогательные методы для преобразования объектов в совместимый тип:
to_date()
преобразует вdatetime.date
to_datetime()
преобразует вdatetime.datetime
.
Пример
Как распарить date/datetimes пришедший из внешнего источника:
fields.Date.to_date(self._context.get('date_from'))
лучшие практики для сравнения Date / Datetime:
- Date поля могут сравниваться только с объектами date.
- Datetime поля могут сравниваться только с объектами datetime.
Предупреждение
Строки, представляющие даты и время, можно сравнивать между собой, однако результат может не соответствовать ожидаемому результату, поскольку строка времени всегда будет больше, чем строка даты, поэтому такая практика очень не рекомендуется.
Стандартные операции с датами и временем, такие как сложение, вычитание или выборка начала/конца периода, доступны через Date
и Datetime
. Эти вспомогательные функции также доступны с помощью импорта odoo.tools.date_utils
.
Примечание
Часовые пояса (Timezones)
Datetime поля хранятся как timestamp без значения timezone
значения полей в базе данных хранятся в нулевом часовом поясе (UTC timezone). Так специально запланировано, т.к. это позволяет базе данных Odoo быть независимой от часового пояса на сервере. Управление часовым поясом происходит происходит непосредственно на стороне клиента.
class odoo.fields.Date[исходный код]
Инкапсулирует объект python класса date
.
static add(value, *args, **kwargs)[исходный код]
Возвращает сумму value
и relativedelta
.
- value – инициирует date или datetime.
- args – позиционные аргументы для передачи непосредственно в
relativedelta
. - kwargs – ключевые аргументы для передачи непосредственно в
relativedelta
.
static context_today(record, timestamp=None)[исходный код]
Возвращает текущую дату в часовом поясе клиента в формате, соответствующем date полям.
Примечание
Этот метод может использоваться для вычисления значений по умолчанию.
- record – набор записей, из которого будет получен часовой пояс.
- timestamp (
datetime
) – необязательное значение datetime, используемое вместо текущей даты и времени (должно быть datetime, обычные даты нельзя конвертировать между часовыми поясами).
static end_of(value, granularity)[исходный код]
Получает окончание временного периода от date или datetime.
- value – инициирует date или datetime.
- granularity – Тип периода в строковом виде, может быть год, квартал, месяц, неделя, день или час.
static start_of(value, granularity)[исходный код]
Получает окончание временного периода от date или datetime.
- value – инициирует date или datetime.
- granularity – тип периода в строковом виде, может быть год, квартал, месяц, неделя, день или час.
static subtract(value, *args, **kwargs)[исходный код]
Возвращает разницу между value
и relativedelta
.
- value – инициирует date или datetime.
- args – позиционные аргументы для передачи непосредственно в
relativedelta
. - kwargs – ключевые аргументы для передачи непосредственно в
relativedelta
.
static to_date(value)[исходный код]
Преобразует значение value
в объект date
.
Предупреждение
Если в качестве значения задан объект datetime, он будет преобразован в объект date, и вся информация, относящаяся к datetime, будет потеряна (HMS, TZ, …).
static to_string(value)[исходный код]
Преобразует date
или datetime
объект в строку.
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
.
static context_timestamp(record, timestamp)[исходный код]
Возвращает указанный timestamp, преобразованный в часовой пояс клиента.
Примечание
Этот метод не предназначен для использования в качестве инициализатора по умолчанию, поскольку поля datetime автоматически преобразуются при отображении на стороне клиента. Для значений по умолчанию используйте метод now()
вместо этого.
- record – набор записей, из которого будет получен часовой пояс.
- timestamp (
datetime
) – значение datetime (выраженное в формате UTC), которое должно быть преобразовано в часовой пояс клиента.
static end_of(value, granularity)[исходный код]
Получает окончание временного периода от date или datetime.
- value – инициирует date или datetime.
- granularity – Тип периода в строковом виде, может быть год, квартал, месяц, неделя, день или час.
static now(*args)[исходный код]
Возвращает текущий день и время в формате, ожидаемом ORM.
Примечание
Эта функция может использоваться для вычисления значений по умолчанию.
static start_of(value, granularity)[исходный код]
Получает окончание временного периода от date или datetime.
- value – инициирует date или datetime.
- granularity – тип периода в строковом виде, может быть год, квартал, месяц, неделя, день или час.
static subtract(value, *args, **kwargs)[исходный код]
Возвращает разницу между value
и relativedelta
.
- value – инициирует date или datetime.
- args – позиционные аргументы для передачи непосредственно в
relativedelta
. - kwargs – ключевые аргументы для передачи непосредственно в
relativedelta
.
static to_datetime(value)[исходный код]
Преобразует ORM value
в значение datetime
.
static to_string(value)[исходный код]
Преобразует объект datetime
или date
в строку.
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
.
Вычисляемые поля
Значение полей может быть вычислено (вместо того, чтобы брать значения сразу из базы данных) с помощью параметра 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»: поля моделей данных могут считываться и записываться непосредственно из записи как ее атрибуты.
Примечание
При доступе к нереляционным полям в НЗ из потенциально нескольких записей используйте mapped()
:
total_qty = sum(self.mapped('qty'))
Доступ к значениям поля также возможен как к элементу словаря (dict), что более элегантно и безопасно, чем getattr()
для динамических имен полей. Установка значения поля запускает обновление базы данных:
>>> record.name
Example Name
>>> record.company_id.name
Company Name
>>> record.name = "Bob"
>>> field = "name"
>>> record[field]
Bob
Предупреждение
Trying to read a field on multiple records will raise an error for non relational fields.
Доступ к реляционному полю(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
, если проверка не прошла.
Предупреждение
@constrains
поддерживает только простые имена полей, имена через точку (Связанные поля, например partner_id.customer
) не поддерживаются и будут игнорироваться.
@constrains
будет срабатывать только в том случае, если объявленные поля в задекорированном методе включены в вызов create
или write
. Это означает, что поля, отсутствующие в представлении, не будут совершать вызов во время создания записи. Переопределение``create`` необходимо, чтобы убедиться, что ограничение всегда будет срабатывать (например, для проверки отсутствия значения).
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. В противном случае он будет отображаться в диалоговом окне по умолчанию.
Предупреждение
@onchange
поддерживает только простые имена полей, имена с точками (связанные поля, например partner_id.tz
) не поддерживаются и будут игнорироваться
Опасно
Т.к. @onchange
возвращает НЗ из псевдо-записей, вызов одного из CRUD методов (create()
, read()
, write()
, unlink()
) для вышеупомянутого НЗ неопределенно поведение, так как они потенциально еще не существуют в базе данных.
Вместо этого просто установите поле записи, как показано в примере выше, или вызовите метод update()
.
Предупреждение
Так же невозможно изменять one2many
или many2many
с помощью onchange. Эту информацию смотрите #2693.
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
),то откатывается до значения компании текущего пользователя.
allowed_company_ids
содержимое ключа контекста.self.user.company_id
)Предупреждение
В режиме sudo проверки работоспособности не применяются! В режиме sudo пользователь может получить доступ к любой компании.
Это позволяет инициировать изменения внутри компании, даже если текущий пользователь не имеет доступа к целевой компании.
Environment.companies
Возвращает НЗ компаний к которым у пользователя есть доступ.
если не указано в контексте (allowed_company_ids
), откатывается до компаний текущего пользователя.
allowed_company_ids
содержимое ключа контекста.self.user.company_ids
)Предупреждение
В режиме sudo проверки работоспособности не применяются! В режиме sudo пользователь может получить доступ к любой компании.
Это позволяет инициировать изменения внутри компании, даже если текущий пользователь не имеет доступа к целевой компании.
Изменение окружения
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)[исходный код]
Возвращает новую версию этого НЗ, прикрепленного к предоставленному окружению.
Environment
) – Предупреждение
Новое окружение не получит преимущества от кэша данных текущего, поэтому в дальнейшем доступ к данным может потребовать дополнительных задержек при повторной выборке из базы данных. Возвращенный набор записей имеет тот же объект предварительной выборки, что и self
.
Model.sudo([flag=True])[исходный код]
Возвращает новую версию этого НЗ с включенным или отключенным режимом суперпользователя, в зависимости от flag
. Режим суперпользователя не меняет текущего пользователя, а просто обходит проверки прав доступа.
Предупреждение
Использование sudo
может привести к тому, что доступ к данным будет пересекать границы правил записи, возможно, смешивая записи, которые должны быть изолированы (например, записи разных компаний в окружении мульти-компаний).
Это может привести к неинтуитивным результатам в методах, которые выбирают одну запись среди многих - например, получение компании по умолчанию или при выборке Спецификаций.
Примечание
Поскольку правила записи и контроля доступа должны быть пересмотрены, новый набор записей не получит преимущества от кэша данных текущей среды, поэтому в дальнейшем доступ к данным может потребовать дополнительных задержек при повторной выборке из базы данных. Возвращенный набор записей имеет тот же объект предварительной выборки, что и self
.
Выполнение SQL запросов
В окружении атрибут cr
является курсором для выполнения транзакции в текущей базе данных и позволяет напрямую выполнять SQL запросы, также применяется для запросов, которые трудно выразить с помощью ORM (например, сложные join’ы), либо по причинам производительности:
self.env.cr.execute("some_sql", param1, param2, param3)
Поскольку модели данных используют один и тот же курсор, а класс Environment
содержит различные кэши, эти кэшидолжны быть недействительными при изменении базы данных с помощью чистого SQL, или дальнейшее использование моделей может стать некогерентным. Необходимо очищать кэши при использовании CREATE
, UPDATE
или DELETE
в SQL, но не SELECT
(который просто читает базу данных).
Примечание
Очистка кэшей может выполняться с использованием метода invalidate_all()
.
Model.invalidate_cache(fnames=None, ids=None)[исходный код]
Сделайте недействительными кэши записей после того, как некоторые записи были изменены. В случаях кода fnames
и ids
имеют значение None
, все кэши очищены.
- fnames – список измененных полей,или
None
для всех полей - ids – список id измененных записей, или
None
для всех
Предупреждение
Выполнение чистого SQL обходит ORM и, как следствие, правила безопасности Odoo. Пожалуйста, убедитесь, что ваши запросы очищены при использовании пользовательского ввода и предпочитаете использовать утилиты ORM, в тех случаях когда вам действительно не нужно использовать SQL-запросы.
Базовые методы ORM
Create/update
Model.create(vals_list) → records[исходный код]
Создает новые записи для модели.
Новая запись инициализируется с использованием значений из списка словарей vals_list
и при необходимости из default_get()
.
list
) – значения для полей модели, как список словарей:
[{'field_name': field_value, ...}, ...]
Для обратной совместимости, vals_list
может быть словарем. Он обрабатывается как одноэлементный список [vals]
, и возвращается одна запись.
смотрите write()
чтобы узнать детали
- AccessError –
- Если у пользователя нет прав на создание объекта
- Если пользователь пытается обойти правила доступа для создания на запрошенном объекте
- ValidationError – Если пользователь пытается ввести недопустимое значение для поля, которое не выбрано
- UserError – Если в иерархии объектов будет создан цикл в результате операции (такой как установка объекта как собственного родителя)
Model.copy(default=None)[исходный код]
Дублирует запись self
, обновляя ее значениями по умолчанию
dict
) – Словарь значений поля для переопределения в исходных значениях скопированной записи, например: {'field_name': overridden_value, ...}
Model.default_get(fields) → default_values[исходный код]
Возвращает значения по умолчанию для полей в fields_list
. Значения по умолчанию определяются контекстом, пользовательскими настройками по умолчанию и самой моделью.
Model.name_create(name) → record[исходный код]
Создает новую запись, вызвав create()
, указав только одно значение: отображаемое имя новой записи.
Новая запись будет инициализироваться с любыми значениями по умолчанию, применимыми к этой модели или предоставляемыми через контекст. Применяется обычное поведение create()
.
name_get()
значение созданной записиModel.write(vals)[исходный код]
Обновляет все записи в текущем НЗ с указанными значениями.
dict
) – поля для обновления и их будущие значения например:: {'foo': 1, 'bar': "Qux"}
установит значение поля foo
в 1
а поля bar
как "Qux"
если такое допустимо (в противном случае будет вызвана ошибка).- AccessError –
- Если у пользователя нет прав на запись для запрашиваемого объекта
- Если пользователь пытается обойти правила доступа для записи на запрошенном объекте
- ValidationError – Если пользователь пытается ввести недопустимое значение для поля, которое не выбрано
- UserError – Если в иерархии объектов будет создан цикл в результате операции (такой как установка объекта как собственного родителя)
- Для числовых полей (
Integer
,Float
) значение должно быть соответствующего типа - Для
Boolean
, значение должно бытьbool
- Для
Selection
, значение должно соответствовать значениям выбора (обычноstr
, иногдаint`
) - Для
Many2one
, значение должно быть id записи Другие нереляционные поля используют строку для значения
Опасно
По историческим причинам и причинам совместимости
Date
иDatetime
поля используют строковые значения (для чтения и запис), а неdate
илиdatetime
. Эти строки даты являются UTC-only и отформатированы в соответствии сodoo.tools.misc.DEFAULT_SERVER_DATE_FORMAT
иodoo.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT
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)
Model.search(args[, offset=0][, limit=None][, order=None][, count=False])[исходный код]
Осуществляет поиск записей на базе args
домен поиска.
- args – домен поиска. Используйте пустой список для соответствия всем записям.
- offset (
int
) – Количество игнорируемых результатов (по умолчанию: none) - limit (
int
) – Максимальное количество возвращаемых записей (по умолчанию: все) - order (
str
) – Строка сортировки - count (
bool
) – Если True, только подсчитывает и возвращает количество совпадающих записей (по умолчанию: False)
- Если пользователь пытается обойти правила доступа для чтения на запрошенном объекте.
Model.search_count(args) → int[исходный код]
Возвращает количество записей в текущей модели и совпадающих с доменом.
Model.name_search(name='', args=None, operator='ilike', limit=100) → records[исходный код]
Ищет записи, у которых есть отображаемое имя, соответствующее заданному шаблону name
, когда совпадает с указанным operator
, а также соответствуют необязательной области поиска (args
).
Это используется, например, для предоставления предложений, основанных на частичном значении для реляционного поля. Иногда можно рассматривать как обратную функцию name_get()
, но это не гарантируется.
Этот метод эквивалентен вызову search()
с поисковым доменом на основе display_name
, а затем примененному name_get()
к результату поиска.
- name (
str
) – Шаблон имени, с которым нужно сопоставить - args (
list
) – необязательный параметр - домен поиска (см.search()
для синтаксиса), указав дальнейшие ограничения - operator (
str
) – оператор домена для сравнения сname
, например'like'
или' = '
. - limit (
int
) – необязательный параметр - максимальное количество возвращаемых записей
(id, text_repr)
для всех совпадающих записей.Model.read([fields])[исходный код]
Читает запрошенные поля для записей в self
, низкоуровневом/RPC-методе. В коде Python предпочитайте browse()
.
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
- Если пользователь не имеет прав на запрашиваемый объект
- Если пользователь пытается обойти правила доступа для чтения на запрошенном объекте
Fields/Views
Model.fields_get([fields][, attributes])[исходный код]
Возвращает определение каждого поля.
Возвращаемое значение - словарь (проиндексированный по имени поля) словарей. Включены поля _inherits’d. Атрибуты string, help и selection (если присутствуют) транслируются.
- allfields – список полей для документа, будут выбраны все поля если, значение не присвоено или не указано
- attributes – список атрибутов описания, возвращаемых для каждого поля, все, если они пусты или не указаны
Model.fields_view_get([view_id | view_type='form'])[исходный код]
Получить подробный состав запрашиваемого представления, например поля, модель, архитектуру представления
- 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.
Примечание
Mostly to negate combinations of criteria Individual criterion generally have a negative form (e.g.
=
->!=
,<
->>=
) which is simpler than negating the positive.
Пример
Для поиска партнера с именем ABC, из Бельгии или Германии, чей язык не английский:
[('name','=','ABC'),
('language.code','!=','en_US'),
'|',('country_id.code','=','be'),
('country_id.code','=','de')]
Этот домен интерпретируется как:
(name is 'ABC')
AND (language is NOT english)
AND (country is Belgium OR Germany)
Unlink
Model.unlink()[исходный код]
Удаляет записи НЗ
- AccessError –
- Если у пользователя нет прав удаления на запрошенном объекте
- Если пользователь пытается обойти правила доступа для удаления на запрошенном объекте
- UserError – Если запись является свойством по умолчанию для других записей
Информация об НЗ
Model.ids
Возвращает список актуальных id записей соответствующих self
.
odoo.models.env
Возвращает окружение предоставленного НЗ.
Environment
Model.exists() → records[исходный код]
Возвращает подмножество записей в self
, которые существуют, и помечает удаленные записи как таковые в кэше. Его можно использовать в качестве теста на записях
if record.exists():
...
По соглашению, новые записи возвращаются как существующие.
Model.ensure_one()[исходный код]
Проверяет, что текущий НЗ содержит одну запись. В противном случае возникает исключение.
len(self) != 1
Model.name_get() → [(id, name), ...][исходный код]
Возвращает текстовое представление для записей в self
. По умолчанию это значение поля display_name
.
(id, text_repr)
для каждой записи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
andset1 > 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
.
# 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
возвращает записи). В последнем случае порядок возвращаемого НЗ произволен.
self
.# 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')
Примечание
Начиная с V13,поддерживается многопользовательский доступ к полям и работает как mapped вызов:
records.partner_id # == records.mapped('partner_id')
records.partner_id.bank_ids # == records.mapped('partner_id.bank_ids')
records.partner_id.mapped('name') # == records.mapped('partner_id.name')
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».
Примечание
Если вы планируете вводить новые исключения, проверьте модуль odoo.addons.test_exceptions
.
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[исходный код]
Предупреждение с возможностью перенаправления пользователя вместо простого отображения предупреждающего сообщения.
exception odoo.exceptions.UserError(msg)[исходный код]
Ошибка, управляемая клиентом.
Обычно, когда пользователь пытается сделать что-то, что не имеет смысла, учитывая текущее состояние записи.
exception odoo.exceptions.ValidationError(msg)[исходный код]
Нарушение ограничений python.
Пример
При попытке создать нового пользователя с логином, который уже существует в БД.