Наборы записей
Добавлено в версии 8.0: На этой странице представлен новый API, добавленный в Odoo 8.0, который станет основным API разработки в будущем. Здесь также предоставлена информация о переносе или переходе со «старого API» версии 7 и более ранних, но вы не найдете здесь документации на старый API. Информацию о старом API ищите в соответствующих документах.
Взаимодействие с моделями данных и записями осуществляется с помощью Наборов Записей (НЗ) - отсортированного набора записей той же модели данных.
Предупреждение
Вопреки тому, что подразумевается под этим именем, в настоящее время в НЗ могут содержаться дубликаты. Это может измениться в будущем.
Методы, определенные для модели данных, выполняются над НЗ, а их self
и представляет собой экземпляр НЗ:
class AModel(models.Model):
_name = 'a.model'
def a_method(self):
# self can be anywhere 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": поля моделей данных могут считываться и записываться непосредственно из записи, но только для ОЗ (НЗ состоящие из одиночной записи). Присвоение значения полю запускает обновление базы данных:
>>> record.name
Example Name
>>> record.company_id.name
Company Name
>>> record.name = "Bob"
>>> field = "name"
>>> record[field]
Bob
Попытка прочитать или записать поле сразу в нескольких записях вызовет ошибку.
Доступ к реляционному полю(Many2one
, One2many
, Many2many
) всегда возвращает НЗ, пустой если поле не задано.
Опасно
каждое присвоение полю какого либо значения запускает обновление базы данных, при одновременной установке нескольких полей или установке полей в нескольких записях (с тем же значением) используйте write()
:
# 3 * len(records) database updates
for record in records:
record.a = 1
record.b = 2
record.c = 3
# len(records) database updates
for record in records:
record.write({'a': 1, 'b': 2, 'c': 3})
# 1 database update
records.write({'a': 1, 'b': 2, 'c': 3})
Запись кеша и предварительная выборка
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
Операции над НЗ
НЗ не изменяемы, но наборы одной и той же модели могут комбинироваться с использованием различных операторов для НЗ, возвращая новые НЗ. Данные операторы не сохраняют порядок сортировки записей внутри НЗ.
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()
, itertools.ifilter
, ...) однако они возвращают либо list
или iterator, удаляя возможность вызывать методы для возвращенных результатов, или использовать операции НЗ.
Поэтому НЗ предоставляют такие операции, которые возвращают объекты НЗ (когда это возможно):
filtered()
Возвращает НЗ, содержащий только записи, удовлетворяющие предоставленной предикатной функции. Предикат может также быть строкой для отфильтрованный по полю, являющемуся истинным или ложным:
# 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")
sorted()
Возвращает НЗ, отсортированный по предоставленной ключевой функции. Если ключ не указан, используется порядок сортировки установленный для модели данных по умолчанию:
# sort records by name records.sorted(key=lambda r: r.name)
mapped()
Применяет предоставленную функцию к каждой записи в НЗ, возвращает НЗ, если результаты являются НЗ:
# returns a list of summing two fields for each record in the set records.mapped(lambda r: r.field1 + r.field2)
Предоставленная функция может быть строкой для получения значений полей:
# returns a list of names records.mapped('name') # returns a recordset of partners record.mapped('partner_id') # returns the union of all partner banks, with duplicates removed record.mapped('partner_id.bank_ids')
Окружение
Класс Environment
хранит различные контекстные данные, используемые ORM: курсор базы данных (формирования запросов к базе данных), текущий пользователь (для проверки прав доступа) и текущий контекст (хранение произвольных метаданных). В окружении также хранятся кэши.
Все НЗ имеют окружение, доступ к которой можно получить с помощью env
и предоставляет доступ к текущему пользователю (user
), курсору (cr
) или контексту(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)
Изменение окружения
Окружение может быть скорректировано на основании НЗ. Данная операция возвращает новую версию НЗ, используя измененное окружение.
sudo()
Создает новое окружение для данного НЗ с правами доступа указанного пользователя, если пользователь не указан, то предоставляются права администратора, (это может быть полезно для обходя ограничений безопасности в ряде случаев), возвращает копию НЗ, который работает в новом окружении:
# create partner object as administrator env['res.partner'].sudo().create({'name': "A Partner"}) # list partners visible by the "public" user public = env.ref('base.public_user') env['res.partner'].sudo(public).search([])
sudo()
Может принимать один позиционный параметр, который заменяет контекст текущего окружения
Может принимать любое количество параметров по ключевому слову, которые добавляются либо в контекст текущего окружения, либо в контекст, заданный во время шага 1
# look for partner, or create one with specified timezone if none is # found env['res.partner'].with_context(tz=a_tz).find_or_create(email_address)
with_env()
Полностью заменяет существующее окружение
Базовые методы ORM
search()
Принимает параметры поиска в виде домена, и возвращает НЗ который удовлетворяют условиям поиска. Может возвращать часть НЗ совпадающих записей (параметры
offset
иlimit
) и может быть отсортирован (параметрorder
):>>> # searches the current model >>> self.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) >>> self.search([('is_company', '=', True)], limit=1).name 'Agrolait'
Совет
для того, чтобы просто проверить, соответствует ли какая-либо запись домену, или посчитать количество записей, которые соотвествуют, используйте
search_count()
create()
Принимает несколько значений полей и возвращает НЗ, содержащий созданную запись:
>>> self.create({'name': "New Name"}) res.partner(78)
write()
Принимает несколько значений полей, записывает их во все записи в своем НЗ. Ничего не возвращает:
self.write({'name': "Newer Name"})
browse()
Принимает идентификатор базы данных или список идентификаторов и возвращает НЗ, полезен, когда идентификаторы записей получены извне Odoo (например запрос-ответ от внешней системы) или когда вызываете методы старого API:
>>> self.browse([7, 18, 12]) res.partner(7, 18, 12)
exists()
Возвращает новый НЗ, содержащий только записи, существующие в базе данных. Может использоваться для проверки того, существует ли запись (например, полученная извне):
if not record.exists(): raise Exception("The record has been deleted")
или после вызова метода, который мог бы удалить некоторые записи:
records.may_remove_some() # only keep records which were not deleted records = records.exists()
ref()
Метод окружения, возвращающий запись, соответствующую предоставленному external id:
>>> env.ref('base.group_public') res.groups(2)
ensure_one()
Проверяет, что НЗ являлся ОЗ (содержит только одну запись), в противном случае возникает ошибка:
records.ensure_one() # is equivalent to but clearer than: assert len(records) == 1, "Expected singleton"
Создание моделей данных
Поля модели данных определяются как ее атрибуты:
from odoo import models, fields
class AModel(models.Model):
_name = 'a.model.name'
field1 = fields.Char()
Предупреждение
Это означает, что вы не можете определить как поле так и метод с одинаковым именем, и они будут конфликтовать
По умолчанию метка поля (видимое пользователем имя) является версией имени поля написанной с большой буквы, это может быть переопределено параметром `string
:
field2 = fields.Integer(string="an other field")
Для различных типов полей и их параметрах смотрите the fields reference.
Значения по умолчанию определяются как параметры полей с присвоенными им значениями:
a_field = fields.Char(default="a value")
или функция, которая должна вычислять и возвращать это самое значение по умолчанию:
def compute_default_value(self):
return self.get_value()
a_field = fields.Char(default=compute_default_value)
Вычисляемые поля
Значение полей может быть вычеслено (вместо того, чтобы читать их прямо из базы данных) с помощью параметра 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
зависимости могут быть указанны в виде ссылки на поле, путь к которому вы описываете через точки:
@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)]
для разрешения значений 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') @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
оnchange: обновление интерфейса на лету
Когда пользователь изменяет значение поля в форме (но еще не сохранил форму), бывает, что полезно автоматически обновлять другие поля на основе введенного им значения, например, обновлять итоговую сумму при изменении значения налога или добавления еще одной позиции в счет.
Вычисляемые поля автоматически проверяются и пересчитываются, им не требуется
onchange
для не вычисляемых полей, используется декоратор
onchange()
чтобы предоставить новые значения полей:@api.onchange('field1', 'field2') # if these fields are changed, call method def check_change(self): if self.field1 < self.field2: self.field3 = True
изменения, выполненные во время работы этого метода, затем отправляются в клиентскую программу и становятся видимыми для пользователя
Как вычисляемые поля так и принадлежащая новому API функция onchange автоматически вызывается клиентом без необходимости добавлять их в представлениях
Можно исключить триггер который вызывает их работу для определенного поля, добавив
on_change="0"
в представлении:<field name="name" on_change="0"/>
обновления интерфейса не будут происходить, если поле редактируется пользователем, даже если в этом поле есть вычисляемые поля или явный вызов onchange.
Примечание
onchange
методы работают с виртуальными записями присвоение значений этим записям не записываются в базу данных, они просто используются для того, чтобы знать, какое значение отправлять обратно клиенту
Предупреждение
It is not possible for a one2many
or many2many
field to modify
itself via onchange. This is a webclient limitation - see #2693.
Использование SQL
В окружении атрибут cr
является курсором для выполнения транзакции в текущей базе данных и позволяет напрямую выполнять SQL, также применяется для запросов, которые трудно выразить с помощью ORM (например, сложные join'ы), либо для производительности причины:
self.env.cr.execute("some_sql", param1, param2, param3)
Поскольку модели данных используют один и тот же курсор, а класс Environment
содержит различные кэши, эти кеши должны быть недействительными при изменении базы данных с помощью чистого SQL, или дальнейшее использование моделей может стать некогерентным. Необходимо очищать кеши при использовании CREATE
, UPDATE
или DELETE
в SQL, но не SELECT
(который просто читает базу данных).
Clearing caches can be performed using the
invalidate_cache()
method of the
BaseModel
object.
Совместимость между новым API и старым API
В настоящее время Odoo переходит со старого (менее упорядоченного) API, возможно потребуется выполнение ряда операций вручную при переходе от одного API к другому:
Уровни RPC (как XML-RPC, так и JSON-RPC) выражаются в терминах старого API, методы, выраженные чисто в новом API, недоступны через RPC
переопределенные методы могут быть вызваны из более старых фрагментов кода, все еще написанных на старом API
Здесь представлены наиболее крупные различия между старыми и новыми API:
значения класса
Environment
(курсор, идентификатор пользователя и контекст) передаются методу явным образомзаписи (
ids
) передаются явным образом в методы и, возможно, не передаются вообщеметоды, как правило, работают со списками идентификаторов вместо НЗ
По умолчанию предполагается, что методы используют новый API и не могут вызываться из старого API.
Совет
вызовы из нового API в старый API транслируются
при использовании нового API вызовы методов, определенных с использованием старого API, автоматически преобразуются «на лету», не нужно делать ничего особенного:
>>> # method in the old API style
>>> def old_method(self, cr, uid, ids, context=None):
... print ids
>>> # method in the new API style
>>> def new_method(self):
... # system automatically infers how to call the old-style
... # method from the new-style method
... self.old_method()
>>> env[model].browse([1, 2, 3, 4]).new_method()
[1, 2, 3, 4]
Два декоратора могут вызвать новый метод для старого API:
model()
метод предоставляется как не использующий идентификаторы, его НЗ, как правило, пуст. Его сигнатура "старого API" выглядит следующим образом
cr, uid, *arguments, context
:@api.model def some_method(self, a_value): pass # can be called as old_style_model.some_method(cr, uid, a_value, context=context)
multi()
метод предоставляется как принимающий список идентификаторов (возможно, пустых), его сигнатура «старого API» выглядит следующим образом
cr, uid, ids, *arguments, context
:@api.multi def some_method(self, a_value): pass # can be called as old_style_model.some_method(cr, uid, [id1, id2], a_value, context=context)
Поскольку новые API-интерфейсы склонны возвращать НЗ, а старые API-интерфейсы возвращают списки идентификаторов, поэтому существует декоратор, управляющий этим:
returns()
предполагается, что функция возвращает НЗ, первым параметром должно быть имя модели данных которой принадлежит НЗ или
self
(для текущей модели).не будет эффекта, если метод вызывается в новом API, но НЗ будет преобразован в список идентификаторов при вызове из старого API:
>>> @api.multi ... @api.returns('self') ... def some_method(self): ... return self >>> new_style_model = env['a.model'].browse(1, 2, 3) >>> new_style_model.some_method() a.model(1, 2, 3) >>> old_style_model = pool['a.model'] >>> old_style_model.some_method(cr, uid, [1, 2, 3], context=context) [1, 2, 3]
Ссылки на модели данных
class odoo.models.Model(pool, cr)[исходный код]
Основной суперкласс для регулярных моделей Odoo, поддерживающих базу данных.
Одоо модели создаются наследованием от этого класса
class user(Model):
...
Позже система создаст экземпляр класса один раз для каждой базы данных (на которой установлен модуль класса).
Структурные атрибуты
_name
наименование бизнес-объекта, в dot-нотации (в пространстве имен модуля)
_rec_name
Альтернативное поле для использования в качестве наименования, используемое osv’s name_get() (по умолчанию: 'name'
)
_inherit
Если атрибут
_name
указан, то он должен содержать имена родительских моделей данных, которые он наследует. Может бытьstr
, если происходит наследование от одного родителяЕсли атрибут
_name
не указан, то происходит расширение конкретной модели данных
Смотрите Наследование и расширение.
_order
Поле указывающее на порядок сортировки при поиске указывать не требуется (по умолчанию сортировка происходит по: 'id'
)
_auto
Должна ли создаваться таблица базы данных (по умолчанию:
True
)Если установлено значение
False
, переопределитеinit`()
для создания таблицы базы данных
Совет
To create a model without any table, inherit
from odoo.models.AbstractModel
_table
Имя таблицы, с которой связана модель данных, созданной при использовании атрибута _auto
, автоматически генерируется по умолчанию.
_inherits
словарь, сопоставляющий _name родительских бизнес-объектов с именами соответствующих полей внешнего ключа для использования:
_inherits = {
'a.model': 'a_field_id',
'b.model': 'b_field_id'
}
реализует композиционное наследование: новая модель данных предоставляет все поля модели _inherits
, но не хранит ни одного из них: сами значения остаются в связанной записи.
Предупреждение
если одно и то же поле определено по нескольким параметрам _inherits
_constraints
Список (constraint_function, message, fields)
, определяющий ограничения для Python. Список полей является ориентировочным
Не рекомендуется, начиная с версии 8.0: use constrains()
_sql_constraints
список триплетов (name, sql_definition, message)
, определяющих SQL-ограничения при создании резервной таблицы
_parent_store
Атрибут parent_left
and [UNKNOWN NODE problematic] для включения быстрых иерархических запросов к записям текущей модели (по умолчанию: False
)
CRUD
create(vals) → record[исходный код]
Создает новую запись для модели.
Новая запись инициализируется с использованием значений из `` vals`` и при необходимости из: meth: ~ .default_get
.
dict
) -- Значения для полей модели, как словарь :: {'field_name': field_value, ...} see: meth: ~ .write
для деталей- AccessError --
Если у пользователя нет прав на создание объекта
Если пользователь пытается обойти правила доступа для создания на запрошенном объекте
- ValidateError -- Если пользователь пытается ввести недопустимое значение для поля, которое не выбрано
- UserError -- Если в иерархии объектов будет создан цикл в результате операции (такой как установка объекта как собственного родителя)
browse([ids]) → records[исходный код]
Возвращает набор записей для идентификаторов, предоставленных в качестве параметра в текущей среде.
Не может принимать идентификаторы, одиночный идентификатор или последовательность идентификаторов.
unlink()[исходный код]
Удаляет записи текущего набора
- AccessError --
Если у пользователя нет прав развязки на запрошенном объекте
Если пользователь пытается обойти правила доступа для развязки на запрошенном объекте
- UserError -- Если запись является свойством по умолчанию для других записей
write(vals)[исходный код]
Обновляет все записи в текущем наборе с предоставленными значениями.
dict
) -- Поля для обновления и значение для них, например: :: {'foo': 1, 'bar': "Qux"} установите поле foo
в 1
, а поле Bar
в "Qux"
если они действительны (иначе это вызовет ошибку).- AccessError --
Если у пользователя нет прав на запись для запрашиваемого объекта
Если пользователь пытается обойти правила доступа для записи на запрошенном объекте
- ValidateError -- Если пользователь пытается ввести недопустимое значение для поля, которое не выбрано
- UserError -- Если в иерархии объектов будет создан цикл в результате операции (такой как установка объекта как собственного родителя)
Для числовых полей (: class:
~ odoo.fields.Integer
,: class:` ~ odoo.fields.Float`) значение должно быть соответствующего типаДля: class:
~ odoo.fields.Boolean
, значение должно быть: class:` python: bool`Для: class:
~ odoo.fields.Selection
, значение должно соответствовать значениям выбора (обычно: class:` python: str`, иногда: class:python: int
)Для: class:
~ odoo.fields.Many2one
, значение должно быть идентификатором базы данных для записиДругие нереляционные поля используют строку для значения
Опасно
По историческим причинам и причинам совместимости: class:
~ odoo.fields.Date
и: class:` ~ odoo.fields.Datetime` поля используют строки как значения (написанные и прочитанные), а не: class:~ python: datetime. Date
или: class:~ python: datetime.datetime
. Эти строки даты являются UTC-only и отформатированы в соответствии с: const:odoo.tools.misc.DEFAULT_SERVER_DATE_FORMAT
и: const:` odoo.tools.misc.DEFAULT_SERVER_DATETIME_FORMAT`: Class:
~ odoo.fields.One2many
и: class:` ~ odoo.fields.Many2many` используют специальный формат "команды" для управления набором записей, хранящихся в / связанных с этим полем.Этот формат представляет собой список триплетов, выполняемых последовательно, где каждый триплет является командой, выполняемой по набору записей. Не все команды применяются во всех ситуациях. Возможные команды:
- Значения(s)
Добавляет новую запись, созданную из предоставленного `` значения`` dict.
- `` (1, id, значения) ``
Обновляет существующую запись id `` id`` со значениями в `` значения``. Нельзя использовать в: мет:
~ .create
.- Ид
Удаляет запись id `` id`` из набора, а затем удаляет его (из базы данных). Нельзя использовать в: мет:
~ .create
.- Ид
Удаляет запись id `` id`` из набора, но не удаляет его. Нельзя использовать: class:
~ odoo.fields.One2many
. Нельзя использовать в: мет:~ .create
.- Ид
Добавляет существующую запись id `` id`` в набор. Нельзя использовать: class:
~ odoo.fields.One2many
.(5, _, _)
Удаляет все записи из набора, что эквивалентно использованию команды `` 3`` для каждой записи явно. Нельзя использовать: class:
~ odoo.fields.One2many
. Нельзя использовать в: мет:~ .create
.- Ids1
Заменяет все существующие записи в наборе списком `` ids``, что эквивалентно использованию команды `` 5``, за которой следует команда `` 4`` для каждого `` id`` в `` ids``.
Примечание
Значения, отмеченные как `` _` в списке выше, игнорируются и могут быть любыми, обычно `` 0`` или `` Ложно``.
read([fields])[исходный код]
Читает запрошенные поля для записей в `` self``, низкоуровневом / RPC-методе. В коде Python предпочитайте: meth: ~ .browse
.
read_group(domain, fields, groupby, offset=0, limit=None, orderby=False, lazy=True)[исходный код]
Получить список записей в виде списка, сгруппированных по заданным полям `` groupby``
- domain -- Список, определяющий критерии поиска [['field_name', 'operator', 'value'], ...]
- fields (
list
) -- Список полей, представленных в виде списка, указанного на объекте - groupby (
list
) -- Список групп по описаниям, по которым записи будут сгруппированы. Групповое описание представляет собой либо поле (тогда оно будет сгруппировано по этому полю), либо поле 'field: groupby_function'. Прямо сейчас единственными поддерживаемыми функциями являются «день», «неделя», «месяц», «квартал» или «год», и они имеют смысл только для полей даты и времени. - offset (
int
) -- Необязательное количество записей для пропуска - limit (
int
) -- Необязательное максимальное количество возвращаемых записей - orderby (
list
) -- Необязательная спецификация `` order by``, для переопределения естественного порядка сортировки групп, см. Также: py: meth:~ osv.osv.osv.search
(поддерживается только для многих полей в настоящее время) - lazy (
bool
) -- Если true, результаты группируются только первой группой, а остальные groupbys помещаются в ключ __context. Если false, все groupbys выполняются за один вызов.
Если пользователь не имеет прав на запрашиваемый объект
Если пользователь пытается обойти правила доступа для чтения на запрошенном объекте
Поиск
search(args[, offset=0][, limit=None][, order=None][, count=False])[исходный код]
Ищет записи, основанные на `` args``: ref: search domain <reference / orm / domains>
.
- args -- : Ref:
Поисковый домен <ссылка / orm / domains>
. Используйте пустой список для соответствия всем записям. - offset (
int
) -- Количество игнорируемых результатов (по умолчанию: нет) - limit (
int
) -- Максимальное количество возвращаемых записей (по умолчанию: все) - order (
str
) -- Строка сортировки - count (
bool
) -- Если «Истина», только подсчитывает и возвращает количество совпадающих записей (по умолчанию: False)
limit`
записей, соответствующих критериям поискаЕсли пользователь пытается обойти правила доступа для чтения на запрошенном объекте.
search_count(args) → int[исходный код]
Возвращает количество записей в текущем совпадении модели: ref: предоставленный домен <reference / orm / domains>
.
name_search(name='', args=None, operator='ilike', limit=100) → records[исходный код]
Искать записи, у которых есть отображаемое имя, соответствующее заданному шаблону `` name``, по сравнению с указанным `` operator``, а также соответствие необязательной области поиска (`` args``).
Это используется, например, для предоставления предложений, основанных на частичном значении для реляционного поля. Иногда можно рассматривать как обратную функцию: meth: ~ .name_get
, но это не гарантируется.
Этот метод эквивалентен вызову: meth: ~ .search
с поисковым доменом на основе` display_name`
, а затем: meth:` ~ .name_get` по результату поиска.
- name (
str
) -- Шаблон имени, который нужно сопоставить - args (
list
) -- Необязательный домен поиска (см.: Meth:~ .search
для синтаксиса), указав дальнейшие ограничения - operator (
str
) -- Domain для сопоставления `` name``, например `` 'like'`` или' = '
. - limit (
int
) -- Необязательное максимальное количество возвращаемых записей
Операции с НЗ
ids
Список фактических идентификаторов записей в этом наборе записей (игнорирует идентификаторы-заполнители для создаваемых записей)
ensure_one()[исходный код]
Проверяет, что текущий recorset содержит одну запись. В противном случае возникает исключение.
exists() → records[исходный код]
Возвращает подмножество записей в `` self``, которые существуют, и помечает удаленные записи как таковые в кеше. Его можно использовать в качестве теста на записях
if record.exists():
...
По соглашению, новые записи возвращаются как существующие.
filtered(func)[исходный код]
Выберите записи в `` self``, чтобы `` func (rec) `` было истинно, и верните их как набор записей.
sorted(key=None, reverse=False)[исходный код]
Возвращает набор записей `` self``, упорядоченный `` key``.
- key -- Либо функцию одного аргумента, который возвращает ключ сравнения для каждой записи, либо имя поля, либо `` None``, в этом случае записи упорядочиваются в соответствии с заказом модели по умолчанию
- reverse -- Если `` True``, вернуть результат в обратном порядке
mapped(func)[исходный код]
Примените `` func`` во всех записях в `` self``, и верните результат в виде списка или набора записей (если `` func`` возвращает записи). В последнем случае порядок возвращаемого набора записей произволен.
Обмен окружением
sudo([user=SUPERUSER])[исходный код]
Возвращает новую версию этого набора записей, прикрепленного к предоставленному пользователю.
По умолчанию это возвращает набор записей `` SUPERUSER``, где контроль доступа и правила записи обходят.
Примечание
Использование `` sudo`` может привести к тому, что доступ к данным будет пересекать границы правил записи, возможно, смешивая записи, которые должны быть изолированы (например, записи разных компаний в среде нескольких компаний).
Это может привести к неинтуитивным результатам в методах, которые выбирают одну запись среди многих - например, получение компании по умолчанию или выбор спецификации.
Примечание
Поскольку правила записи и контроля доступа должны быть пересмотрены, новый набор записей не получит преимущества от кэша данных текущей среды, поэтому в дальнейшем доступ к данным может потребовать дополнительных задержек при повторной выборке из базы данных. Возвращенный набор записей имеет тот же объект предварительной выборки, что и `` self``.
with_context([context][, **overrides]) → records[исходный код]
Возвращает новую версию этого набора записей, присоединенного к расширенному контексту.
Расширенным контекстом является либо предоставленный контекст, в котором объединены `` 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}
with_env(env)[исходный код]
Возвращает новую версию этого набора записей, прикрепленного к предоставленной среде.
Предупреждение
Новая среда не получит преимущества от кэша данных текущей среды, поэтому в дальнейшем доступ к данным может потребовать дополнительных задержек при повторной выборке из базы данных. Возвращенный набор записей имеет тот же объект предварительной выборки, что и `` self``.
Запросы полей и представлений
fields_get([fields][, attributes])[исходный код]
Возвращает определение каждого поля.
Возвращаемое значение - словарь (обозначается именем поля) словарей. Включены поля _inherits'd. Атрибуты string, help и selection (если присутствуют) транслируются.
- allfields -- Список полей для документа, все, если они пусты или не указаны
- attributes -- Список атрибутов описания, возвращаемых для каждого поля, все, если они пусты или не указаны
fields_view_get([view_id | view_type='form'])[исходный код]
Получить подробный состав запрашиваемого представления, например поля, модель, вид архитектуры
- view_id -- Идентификатор представления или Нет
- view_type -- Тип представления, возвращаемого, если view_id равно None ('form', 'tree', ...)
- toolbar -- True для включения контекстных действий
- submenu -- Устарело
- AttributeError --
Если унаследованное представление имеет неизвестную позицию для работы с другими, чем «до», «после», «внутри», «заменить»,
Если в родительском представлении обнаружен какой-либо тег, отличный от 'position'
- Invalid ArchitectureError -- Если есть вид, отличный от формы, дерева, календаря, поиска и т. Д., Определенных в структуре
Различные методы
default_get(fields) → default_values[исходный код]
Возвращайте значения по умолчанию для полей в `` fields_list``. Значения по умолчанию определяются контекстом, пользовательскими настройками по умолчанию и самой моделью.
copy(default=None)[исходный код]
Дублировать запись `` self``, обновляя ее значениями по умолчанию
dict
) -- Словарь значений поля для переопределения в исходных значениях скопированной записи, например: `` {'field_name': overridden_value, ...} ``name_get() → [(id, name), ...][исходный код]
Возвращает текстовое представление для записей в `` self``. По умолчанию это значение поля `` display_name``.
name_create(name) → record[исходный код]
Создайте новую запись, вызвав: meth: ~ .create
, указав только одно значение: отображаемое имя новой записи.
Новая запись будет инициализироваться с любыми значениями по умолчанию, применимыми к этой модели или предоставляемыми через контекст. Применяется обычное поведение: meth: ~ .create
.
~ .name_get
для созданной записиАвтоматические поля
id
Идентификатор field
_log_access
Должны быть созданы поля для журналирования действий пользователей (create_date
, write_uid
, ...) (по умолчанию: True
)
create_date
Дата создания записи
ласс: ~ odoo.field.Datetime
create_uid
Реляционное поле для пользователя, создавшего запись
res.users
write_date
Дата последнего изменения записи
ласс: ~ odoo.field.Datetime
write_uid
Реляционное поле для пользователя, который последним изменил запись
res.users
Зарезервированные имена полей
Несколько имен полей зарезервированы для предопределенных сценариев, которые отличаются от автоматически заполняемых полей. Они должны быть определены в модели данных, когда настраивается желаемое поведение:
name
значение по умолчанию для _rec_name
, используется для отображения записей в контексте, где требуется репрезентативное "наименование".
active
позволяет отключать глобальную видимость записи, если параметр active
установлен на False
, запись невидима в большинстве поисковых запросов и подсказок
sequence
Изменяемые критерии сортировки, дпозволяет перетаскивать записи модели данных в представлениях в виде списка
state
этапы жизненного цикла объекта, используемые атрибутом состояния
в классе : fields
parent_id
используется для упорядочивания записей в древовидной структуре и включения оператора child_of
в доменах
parent_left
используется с _parent_store
, позволяет быстрее обращаться к древовидной структуре
parent_right
смотрите parent_left
Декораторы методов
Этот модуль предоставляет элементы для управления двумя разными стилями API, а именно «старым стилем» и «новым стилем».
В старом стиле такие параметры как курсор базы данных, идентификатор пользователя, словарь контекста и идентификаторы записи (обычно обозначаемые как cr
, uid
, context
, ids
) Передаются явным образом всем методам. В в новом стиле эти параметры скрыты в экземплярах модели данных, что придает ему более объектно-ориентированный вид.
Например, выражения:
model = self.pool.get(MODEL)
ids = model.search(cr, uid, DOMAIN, context=context)
for rec in model.browse(cr, uid, ids, context=context):
print rec.name
model.write(cr, uid, ids, VALUES, context=context)
также может быть записано как:
env = Environment(cr, uid, context) # cr, uid, context wrapped in env
model = env[MODEL] # retrieve an instance of MODEL
recs = model.search(DOMAIN) # search returns a recordset
for rec in recs: # iterate over the records
print rec.name
recs.write(VALUES) # update all records in recs
Методы, написанные в "старом" стиле, автоматически оформляются, следуя некоторым эвристическим методам, основанным на именах параметров.
odoo.api.multi(method)[исходный код]
Задекорируйте метод в новом стиле, где self
- НЗ. Этот метод обычно определяет операцию над записями. Таким способом:
@api.multi
def method(self, args):
...
может быть вызван как в старом, так и в новом стиле, например:
# recs = model.browse(cr, uid, ids, context)
recs.method(args)
model.method(cr, uid, ids, args, context=context)
odoo.api.model(method)[исходный код]
Задекорируйте метод в новом стиле, где self
- НЗ, но его содержимое не релевантно, только модель данных. Таким способом:
@api.model
def method(self, args):
...
может быть вызван как в старом, так и в новом стиле, например:
# recs = model.browse(cr, uid, ids, context)
recs.method(args)
model.method(cr, uid, args, context=context)
Обратите внимание, что ids
передаются в методы только в старом стиле.
odoo.api.depends(*args)[исходный код]
Возвращает декоратор, который задает зависимости полей для метода "compute" (для вычисляемых полей в новом стиле). Каждый аргумент должен быть строкой, состоящей из разделенных точками последовательностей имен полей:
pname = fields.Char(compute='_compute_pname')
@api.one
@api.depends('partner_id.name', 'partner_id.is_company')
def _compute_pname(self):
if self.partner_id.is_company:
self.pname = (self.partner_id.name or "").upper()
else:
self.pname = self.partner_id.name
В качестве аргумента можно передать одну функцию. В этом случае зависимости задаются вызовом функции поля модели данных.
odoo.api.constrains(*args)[исходный код]
Декорирует проверку ограничений. Каждый аргумент должен быть именем поля, используемым для проверки:
@api.one
@api.constrains('name', 'description')
def _check_description(self):
if self.name == self.description:
raise ValidationError("Fields name and description must be different")
Вызывается для записей в новом стиле, в которых одно из именованных полей было изменено.
Должен быть вызван класс ValidationError
, если проверка не прошла.
Предупреждение
@constrains
поддерживает только простые имена полей, имена через точку (поля реляционных полей, например partner_id.customer
) не поддерживаются и будут игнорироваться
@constrains
will be triggered only if the declared fields in the
decorated method are included in the create
or write
call.
It implies that fields not present in a view will not trigger a call
during a record creation. A override of create
is necessary to make
sure a constraint will always be triggered (e.g. to test the absence of
value).
odoo.api.onchange(*args)[исходный код]
Возвращает декоратор, чтобы задекорировать метод onchange для заданных полей. Каждый аргумент должен быть именем поля:
@api.onchange('partner_id')
def _onchange_partner(self):
self.message = "Dear %s" % (self.partner_id.name or "")
В представлении в виде формы где появляется поле, метод вызывается, когда одно из заданных полей изменяется. Метод вызывается в псевдо-записи, содержащей значения, присутствующие в форме. Назначения полей в этой записи автоматически отправляются обратно клиенту.
Метод может возвращать словарь для изменения полей домена и выводить предупреждающее сообщение, как в старом API:
return {
'domain': {'other_id': [('partner_id', '=', partner_id)]},
'warning': {'title': "Warning", 'message': "What is this?"},
}
Предупреждение
@onchange
поддерживает только простые имена полей, имена с точками (поля реляционных полей, например partner_id.tz
) не поддерживаются и будут игнорироваться
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
и 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.one(method)[исходный код]
Задекорируйте метод нового стиля, где self
должен быть ОЗ экземпляром. Декорированный метод автоматически перебирает записи и составляет список с результатами. Если метод задекорирован returns()
, он складывает результирующие экземпляры. Таким способом:
@api.one
def method(self, args):
return self.name
может быть вызван как в старом, так и в новом стиле, например:
# recs = model.browse(cr, uid, ids, context)
names = recs.method(args)
names = model.method(cr, uid, ids, args, context=context)
Не рекомендуется, начиная с версии 9.0: one()
часто делает код менее понятным и ведет себя так, как могут не ожидать разработчики и читатели.
Настоятельно рекомендуется использовать multi()
и либо выполнить итерацию по НЗ через self
, либо убедиться, что НЗ является одной записью с ensure_one()
.
odoo.api.v7(method_v7)[исходный код]
Задекорируйте метод, который поддерживает только api в старом стиле. Новый API-интерфейс может быть предоставлен переопределением метода с тем же именем и декоратором v8()
:
@api.v7
def foo(self, cr, uid, ids, context=None):
...
@api.v8
def foo(self):
...
Особую осторожность следует проявлять, если один метод вызывает другой, потому что метод может быть переопределен! В этом случае следует вызвать метод из текущего класса (скажем, MyClass
), например
@api.v7
def foo(self, cr, uid, ids, context=None):
# Beware: records.foo() may call an overriding of foo()
records = self.browse(cr, uid, ids, context)
return MyClass.foo(records)
Обратите внимание, что метод-враппер использует docstring первого метода.
odoo.api.v8(method_v8)[исходный код]
Задекорируйте метод, который поддерживает только API-интерфейс нового стиля. Для api старого стиля можно переопределить метод с тем же именем и задекорировать его v7()
:
@api.v8
def foo(self):
...
@api.v7
def foo(self, cr, uid, ids, context=None):
...
Обратите внимание, что метод-враппер использует docstring первого метода.
Поля
Основные поля
class odoo.fields.Field(string=<object object>, **kwargs)[исходный код]
Дескриптор поля содержит определение поля и управляет доступом и присвоением соответствующего поля для записей. При инициализации поля могут быть предоставлены следующие атрибуты:
- string -- Метка поля, видимая пользователями (строка); Если не установлено, ORM берет имя поля в классе (с заглавной буквы).
- help -- Всплывающая подсказка поля, видимая пользователями (строка)
- readonly -- Является ли поле readonly (логическим, по умолчанию `` False``)
- required -- Требуется ли значение поля (логическое значение, по умолчанию `` Ложное_`)
- index -- Является ли поле индексированным в базе данных (логическое, по умолчанию `` Ложное``)
- default -- Значение по умолчанию для поля; Это либо статическое значение, либо функция, выполняющая набор записей и возвращающая значение; Используйте `` default = None``, чтобы сбросить значения по умолчанию для поля
- states -- Словарь значений состояния отображения в списки пар атрибут-значение пользовательского интерфейса; Возможные атрибуты: «readonly», «required», «invisible». Примечание. Любое состояние на основе состояния требует, чтобы в пользовательском интерфейсе клиентской стороны было доступно значение поля `` состояние``. Обычно это делается путем включения его в соответствующие представления, возможно сделанные невидимыми, если это не относится к конечному пользователю.
- groups -- Список групповых xml-идентификаторов (строка), разделённых запятыми; Это ограничивает доступ к полям только для пользователей указанных групп
- copy (
bool
) -- Следует ли копировать значение поля при дублировании записи (по умолчанию: `` True`` для обычных полей, `` False`` для `` one2many`` и вычисляемых полей, включая поля свойств и связанные поля) - oldname (
string
) -- Предыдущее имя этого поля, чтобы ORM мог автоматически переименовать его при миграции
Вычисляемые поля
Можно определить поле, значение которого вычисляется вместо простого чтения из базы данных. Атрибуты, специфичные для вычисляемых полей, приведены ниже. Чтобы определить такое поле, просто укажите значение атрибута `` compute``.
- compute -- Имя метода, который вычисляет поле
- inverse -- Имя метода, который инвертирует поле (необязательно)
- search -- Имя метода, реализующего поиск по полю (необязательно)
- store -- Хранится ли поле в базе данных (логическое значение, по умолчанию `` Ложное`` в вычисленных полях)
- compute_sudo -- Должно ли поле быть пересчитано в качестве суперпользователя для обхода прав доступа (логическое, по умолчанию `` False``)
Методы, приведенные для `` compute``, `` inverse`` и `` search``, являются модельными методами. Их подпись показана в следующем примере
upper = fields.Char(compute='_compute_upper',
inverse='_inverse_upper',
search='_search_upper')
@api.depends('name')
def _compute_upper(self):
for rec in self:
rec.upper = rec.name.upper() if rec.name else False
def _inverse_upper(self):
for rec in self:
rec.name = rec.upper.lower() if rec.upper else False
def _search_upper(self, operator, value):
if operator == 'like':
operator = 'ilike'
return [('name', operator, value)]
Метод compute должен назначить поле для всех записей набора записей. Декоратор: meth: odoo.api.depends
должен быть применен к методу compute для указания зависимостей полей; Эти зависимости используются, чтобы определить, когда нужно пересчитывать поле; Пересчет является автоматическим и гарантирует согласованность кэша / базы данных. Обратите внимание, что один и тот же метод может использоваться для нескольких полей, вам просто нужно назначить все указанные поля в методе; Метод будет вызываться один раз для всех этих полей.
По умолчанию вычисленное поле не сохраняется в базе данных и вычисляется «на лету». Добавление атрибута `` store = True`` будет хранить значения поля в базе данных. Преимущество хранимого поля в том, что поиск по этому полю выполняется самой базой данных. Недостатком является то, что для обновления необходимо обновить базу данных.
Обратный метод, как следует из его имени, делает инверсию метода compute: вызванные записи имеют значение для поля, и вы должны применять необходимые изменения для зависимостей полей, чтобы вычисление давало ожидаемое значение. Обратите внимание, что вычисляемое поле без обратного метода по умолчанию доступно только для чтения.
Метод поиска вызывается при обработке доменов перед выполнением фактического поиска по модели. Он должен возвращать домен, эквивалентный условию: `` значение оператора поля``.
Реляционные поля
Значение связанного поля задается последовательностью реляционных полей и чтением поля по достигнутой модели. Полная последовательность полей для перемещения определяется атрибутом
Некоторые атрибуты полей автоматически копируются из исходного поля, если они не переопределены: `` строка``, `` help``, `` readonly``, `` required`` (только если все поля в последовательности обязательны) , `` Группы``, цифры'
,` размер`
,` переводить`
,` санировать``
,` выбор`
,` comodel_name`
,` домен`
,` context`
. Все семантически-свободные атрибуты копируются из исходного поля.
По умолчанию значения связанных полей не сохраняются в базе данных. Добавьте атрибут `` store = True``, чтобы он сохранялся, как и вычисляемые поля. Связанные поля автоматически пересчитываются при изменении их зависимостей.
Зависимые от компании поля
Ранее известные как поля свойств, значение этих полей зависит от компании. Другими словами, пользователи, принадлежащие к разным компаниям, могут видеть разные значения поля для данной записи.
Пошаговое определение
Поле определяется как атрибут класса в классе модели. Если модель расширена (см.: Класс: ~ odoo.models.Model
), можно также расширить определение поля, переопределив поле под тем же именем и тем же типом в подклассе. В этом случае атрибуты поля берутся из родительского класса и переопределяются атрибутами, указанными в подклассах.
Например, второй класс ниже только добавляет всплывающую подсказку в поле `` 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")
class odoo.fields.Char(string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields._String
Поле основной строки может быть ограничено по длине, обычно отображается в виде строки с одной строкой в клиентах.
- size (
int
) -- Максимальный размер значений, хранящихся для этого поля - translate -- Включить перевод значений поля; Используйте `` translate = True`` для перевода значений полей в целом; `` Translate`` также может быть вызываемым, так что
translate (callback, value)
переводит
значение`
с помощью`callback (term)
[UNKNOWN NODE problematic], чтобы получить перевод терминов.
class odoo.fields.Boolean(string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields.Field
class odoo.fields.Integer(string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields.Field
class odoo.fields.Float(string=<object object>, digits=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields.Field
Цифры точности задаются атрибутом
class odoo.fields.Text(string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields._String
Очень похоже на: class: ~ .Char
, но используется для более длинного содержимого, не имеет размера и обычно отображается как многострочное текстовое поле.
translate (callback, value)
переводит
значение`
с помощью` callback (term)
[UNKNOWN NODE problematic], чтобы получить перевод терминов.class odoo.fields.Selection(selection=<object object>, string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields.Field
- selection -- Указывает возможные значения для этого поля. Он задается либо как список пар («значение», «строка»), либо как модельный метод, либо как имя метода.
- selection_add -- Предоставляет расширение выбора в случае переопределенного поля. Это список пар (`` значение``, `` строка``).
Атрибут `` selection`` является обязательным, за исключением случая: ref: related fields <field-related>
или: ref: field extensions <field-incremental-definition>
.
class odoo.fields.Html(string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields._String
class odoo.fields.Date(string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields.Field
static context_today(record, timestamp=None)[исходный код]
Возвращает текущую дату в часовом поясе клиента в формате, соответствующем полям даты. Этот метод может использоваться для вычисления значений по умолчанию.
static from_string(value)[исходный код]
Преобразуйте значение ORM `` значение`` в значение: class: date
.
static to_string(value)[исходный код]
Преобразовать a: class: значение date
в формат, ожидаемый ORM.
static today(*args)[исходный код]
Возвращает текущий день в формате, ожидаемом ORM. Эта функция может использоваться для вычисления значений по умолчанию.
class odoo.fields.Datetime(string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields.Field
static context_timestamp(record, timestamp)[исходный код]
Возвращает заданную временную метку, преобразованную в часовой пояс клиента. Этот метод * не * предназначен для использования в качестве инициализатора по умолчанию, поскольку поля даты и времени автоматически преобразуются при отображении на стороне клиента. Для значений по умолчанию: meth: fields.datetime.now
следует использовать вместо этого.
static from_string(value)[исходный код]
Преобразуйте значение ORM в значение: class: datetime
.
static now(*args)[исходный код]
Возвращает текущий день и время в формате, ожидаемом ORM. Эта функция может использоваться для вычисления значений по умолчанию.
static to_string(value)[исходный код]
Преобразуйте значение типа: datetime в формат, ожидаемый ORM.
Реляционные поля
class odoo.fields.Many2one(comodel_name=<object object>, string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields._Relational
Значение такого поля - это набор записей размера 0 (нет записи) или 1 (одна запись).
- comodel_name -- Имя целевой модели (строка)
- domain -- Необязательный домен для установки значений кандидатов на стороне клиента (домен или строка)
- context -- Необязательный контекст для использования на стороне клиента при обработке этого поля (словаря)
- ondelete -- Что делать, если упомянутая запись удалена; Возможные значения: `` 'set null```,
' restrict'
, `` 'cascade'[UNKNOWN NODE problematic][UNKNOWN NODE problematic] - auto_join -- Генерируются ли JOIN при поиске в этом поле (логическое значение, по умолчанию `` False``)
- delegate -- Установите его в `` True``, чтобы сделать поля целевой модели доступными из текущей модели (соответствует `` _inherits``)
Атрибут `` comodel_name`` является обязательным, за исключением случаев, касающихся связанных полей или расширений полей.
class odoo.fields.One2many(comodel_name=<object object>, inverse_name=<object object>, string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields._RelationalMulti
Поле One2many; Значение такого поля является набором записей всех записей в `` comodel_name``, так что поле `` inverse_name`` равно текущей записи.
- comodel_name -- Имя целевой модели (строка)
- inverse_name -- Имя инверсного поля `` Many2one`` в `` comodel_name`` (строка)
- domain -- Необязательный домен для установки значений кандидатов на стороне клиента (домен или строка)
- context -- Необязательный контекст для использования на стороне клиента при обработке этого поля (словаря)
- auto_join -- Генерируются ли JOIN при поиске в этом поле (логическое значение, по умолчанию `` False``)
- limit -- Необязательное ограничение на чтение (целое)
Атрибуты `` comodel_name`` и `` inverse_name`` обязательны, за исключением соответствующих полей или расширений полей.
class odoo.fields.Many2many(comodel_name=<object object>, relation=<object object>, column1=<object object>, column2=<object object>, string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields._RelationalMulti
Поле Many2many; Значением такого поля является набор записей.
Атрибут `` comodel_name`` является обязательным, за исключением случаев, касающихся связанных полей или расширений полей.
- relation -- Необязательное имя таблицы, в которой хранится отношение в базе данных (строка)
- column1 -- Необязательное имя столбца, ссылающееся на "эти" записи в таблице
relation
(строка) - column2 -- Необязательное имя столбца, ссылающегося на "те" записи в таблице
relation
(строка)
Атрибуты `` отношение``, `` column1`` и `` column2`` являются необязательными. Если не указано, имена автоматически генерируются из имен моделей, если model_name`
и` comodel_name`
различны!
- domain -- Необязательный домен для установки значений кандидатов на стороне клиента (домен или строка)
- context -- Необязательный контекст для использования на стороне клиента при обработке этого поля (словаря)
- limit -- Необязательное ограничение на чтение (целое)
class odoo.fields.Reference(selection=<object object>, string=<object object>, **kwargs)[исходный код]
Базовые классы:: class: odoo.fields.Selection
Наследование и расширение
Odoo обеспечивает три различных механизма для расширения моделей данных по модульному принципу:
создание новой модели данных из уже существующей, добавляя новую информацию в копию, но оставляя исходный модуль как есть
расширение моделей данных, определенных в других модулях, заменяя предыдующую версию
делегировании некоторых полей моделей данных к записям, которые они содержат

Классическое наследование
При использовании атрибутов _inherit
и _name
вместе, Odoo создает новую модель, используя уже существующую (с помощью атрибута : attr: ~ Odoo.models.Model._inherit
) в качестве базиса. Новая модель получает все поля, методы и мета-информацию (defaults & al) от базисной модели данных.
class Inheritance0(models.Model):
_name = 'inheritance.0'
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'
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'
name = fields.Char(default="A")
class Extension1(models.Model):
_inherit = 'extension.0'
description = fields.Char(default="Extended")
env = self.env
{'name': "A", 'description': "Extended"}
даст следующий результат:
Примечание
это приведет к автомтически созданным полям, если они не были отключены
Делегирование
Третий механизм наследования обеспечивает большую гибкость (существует возможность изменения во врмемя выполнения) но требует больше мощностей: использу _inherits
модель данных делегирует поиск любого поля, не найденного в текущей модели данных "дочерним" моделям данных. Делегирование осуществляется с помощью Reference
, полей автомтически установленных на родительской модели данных:
class Child0(models.Model):
_name = 'delegation.child0'
field_0 = fields.Integer()
class Child1(models.Model):
_name = 'delegation.child1'
field_1 = fields.Integer()
class Delegating(models.Model):
_name = 'delegation.parent'
_inherits = {
'delegation.child0': 'child0_id',
'delegation.child1': 'child1_id',
}
child0_id = fields.Many2one('delegation.child0', required=True, ondelete='cascade')
child1_id = fields.Many2one('delegation.child1', required=True, ondelete='cascade')
record = env['delegation.parent'].create({
'child0_id': env['delegation.child0'].create({'field_0': 0}).id,
'child1_id': env['delegation.child1'].create({'field_1': 1}).id,
})
record.field_0
record.field_1
даст результат:
0
1
есть возможность сделать запись прямо в делегированное поле:
record.write({'field_1': 4})
Предупреждение
когда используете наследование через делегирование, методы не наследуются, только поля
Домены
Домен - это список критериев, каждый критерий состоит из трех частей ( является либо списком
или кортежем
) (имя_поля, оператор, значние)
где:
имя_поля
(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
).
value
тип переменной, который должен быть сопоставим (через
operator
) с названным полем
Критерии домена могут быть объединены с помощью логических операторов в виде prefix:
'&'
логическое И, операция по умолчанию для объединения критериев, следующих друг за другом. Arity 2 (испольузет следующие 2 кртерия или комбинации).
'|'
логическое ИЛИ, arity 2.
'!'
Логическое НЕ, arity 1.
Совет
Главным образом, чтобы свести на нет комбинации критериев
Индивидуальный критерий как правило, имеет отрицательную форму(например:
=
->!=
,<
->>=
), что является более простым способом достичь нужного результата, чем отрицание положительных результатов .
Пример
Для поиска партнера с именем 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)
Портирование со старого API на новый API
в новом API необходимо исключить списки идентификаторов, вместо этого использовать НЗ
методы, все еще написанные на старом API, должны автоматически работать с ORM, отсутствует необходимость переключения на старый API, просто вызывайте их, как если бы они были методом нового API. Смотрите Автоматический проброс старых API-методов для более подробной информации.
search()
возвращает НЗ, не имеет смысла, например, при просмотре его результатаfields.related
иfields.function
заменяются с использованием нормального типа поля с параметромrelated=
илиcompute=
функции
depends()
вcompute=
методах должны быть полными, они должны отобразить все поляполя, которые использует метод для вычисления. Лучше иметь слишком много зависимостей (будет пересчитывать поле в тех случаях, когда это не требуется), чем недостаточное их количество (забудет пересчитать поле, в следствии чего значения будут неверны)удалить все методы
onchange
для вычисляемых полей. Вычисляемые поля автоматически пересчитываются при изменении значения одного из полей, указанных в зависимостях и используются для автоматической генерацииonchange
клиентомдекораторы
model()
иmulti()
предназначены для объединения при вызове из контекста старого API, для внутренних или простых методов нового API (например, compute) они бесполезнызамените
_default
, замените параметромdefault=
в соответствующих поляхесли параметр поля
string=
- это наименование поля с большой буквы:name = fields.Char(string="Name")
он бесполезен и должен быть удален
параметр
multi=
ничего не делает в полях в новом API, он использует одни и те же методы что иcompute=
во всех соответствующих полях для достижения одного и того же результатапредоставляет
compute=
,inverse=
иsearch=
методы по имени (как строку), это делает их переопределяемыми (устраняет необходимость в промежуточной функции "трамплине")дважды проверьте, что все поля и методы имеют разные имена, в случае совпадения их имен предупреждение будет отсутствовать (поскольку Python обрабатывает его до того, как Odoo увидит что-либо)
нормальный импорт для нового API
from odoo import fields, models
. Если необходимы декораторы совместимости, используйтеfrom odoo import api, fields, models
.избегайте
one()
декоратор, он, вероятно, не делает то, что вы ожидаетеУдалите явное определение полей
create_uid
,create_date
,write_uid
иwrite_date
: они теперь создаются как обычные "законные" поля и могут читаться и записываться, как и любые другиекогда прямое преобразование невозможно (семантика не может быть преобразована), или версия «старого API» нежелательна и может быть улучшена до нового API, можно использовать совершенно разные «старые API» и «новые API» для одного и того же имени метода, используя
v8()
. Метод должен быть сначала определен с использованием старого API и задекорированv7()
, затем он должен быть переопределен с использованием того же самого имени, но с новым API-интерфейсом и задекорированv8()
. Вызовы из старого API-интерфейса будут отправлены в первую реализацию, а вызовы из контекста нового API будут отправлены во вторую реализацию. Одна реализация может вызывать (и часто делает) оба вызова, переключая контекст.Опасно
использование этих декораторов делает методы чрезвычайно трудными для переопределения их труднее понять и документировать
использование
_columns
or_all_columns
следует заменить на by_fields
, которые предоставляют доступ экземплярам с новым APIodoo.fields.Field
(чаще чемodoo.osv.fields._column
).Не сохраненные вычисленные поля, созданные с использованием нового API, недоступны в
_columns
и могут быть проверены только через_fields
переназначение
self
в методе, вероятно, не нужно и может нарушить интроспекцию трансляцииmanage
при попытке использовать новый API в контекстах, где он еще не был настроен, например, новые потоки или интерактивная среда Python:>>> from odoo import api, modules >>> r = modules.registry.RegistryManager.get('test') >>> cr = r.cursor() >>> env = api.Environment(cr, 1, {}) Traceback (most recent call last): ... AttributeError: environments >>> with api.Environment.manage(): ... env = api.Environment(cr, 1, {}) ... print env['res.partner'].browse(1) ... res.partner(1,)
Автоматический проброс старых API-методов
Когда модели инициализируются, все методы автоматически сканируются и пробрасываются, если они похожи на модели данных, объявленные в старом API. Этот проброс делает их прозрачно вызываемыми из методов нового API.
Методы сопоставляются как «старый-API», если их второй позиционный параметр (после self
) называется cr
или cursor
. Система также распознает третий позиционный параметр, называемый uid
или user
, а четвертый называется id
или ids
. Он также распознает наличие любого параметра, вызываемого с помощью context
.
При вызове таких методов из контекста нового API система автоматически заполнит согласованные параметры из текущего Environment
(for cr
, user
and context
) или текущий НЗ (для id
and ids
).
В редких случаях, когда это необходимо, проброс можно настроить, задекорировав метод старого API:
полностью отключить его, задекорировав метод с помощью
noguess()
не будет никакого проброса, и методы будут вызываться точно таким же образом из нового и старого APIявным образом определяя проброс, это в основном подходит для методов, которые неправильно сопоставляются (потому что параметры названы непредвиденными способами):
cr()
автоматически добавит текущий курсор к явно заданным параметрам, позиционно
cr_uid()
автоматически добавит текущий курсор и идентификатор пользователя к явно заданным параметрам
cr_uid_ids()
автоматически добавит текущий курсор, идентификатор пользователя и идентификаторы набора записей в явно заданные параметры
cr_uid_id()
будет выполнять перебор по текущему набору записей и вызывать метод один раз для каждой записи, добавляя к текущему курсору, идентификатору пользователя и идентификатору записи явно указанные параметры.
Опасно
результатом работы враппера является всегда список при вызове из контекста нового API
Все эти методы имеют версию
_context
-suffixed (напримерcr_uid_context()
), которая также передает текущий контекст по ключевому слову.двойная реализация, использующая
v7()
иv8()
будет игнорироваться, поскольку они предоставляют свои собственные "пробросы"