odoo-14.0.post20221212.tar
Поля модели определяются как свойства самой модели.
from odoo import models, fields
class AModel(models.Model):
_name = 'a.model.name'
field1 = fields.Char()
предупреждать Имя поля и имя метода не могут совпадать. Последнее определенное имя метода и функции перезапишет то же имя, определенное ранее.
По умолчанию метка поля (Lable, то есть видимое пользователю имя поля) — это значение после того, как начальные буквы соответствующего имени поля будут изменены на прописные. Можно передать. string
Измените атрибут поля, чтобы изменить метку поля.
field2 = fields.Integer(string="Field Label")
Сносноdefault
,Определить цену по умолчанию:
name = fields.Char(default="a value")
Значения по умолчанию также можно получить через функции:
def _default_name(self):
return 'Title'
name = fields.Char(default=lambda self: self._default_name())
class odoo.models.BaseModel
[исходный код]
Базовый класс для моделей Odoo. Режим Odoo может создавать модель, наследуя следующие классы:
Model
Для общей модели персистентности базы данныхTransientModel
Используется для временных данных, хранящихся в базе данных, но время от времени автоматически удаляемых.AbstractModel
Абстрактный родительский класс для совместного использования нескольких наследуемых модулей, не создает таблицы моделей в базе данных.Система автоматически создает экземпляр каждой модели один раз для каждой базы данных. Эти экземпляры представляют модели, доступные в каждой базе данных, в зависимости от модулей, установленных в этой базе данных. Фактический класс для каждого экземпляра создается на основе класса Python, который создал и унаследовал соответствующую модель.
Каждый экземпляр модели представляет собой «набор записей», упорядоченный набор записей модели. Набор записей состоит из browse()
, search()
или Доступ к полям и методам появились. Записи не имеют явного представления: одна запись представляет собой набор записей из одной записи.
Чтобы создать класс, не требующий создания экземпляра, вы можете использовать _register
Настройки недвижимостидляFalse
_auto= False
Следует ли создавать таблицу базы данных. Если установлено значение False
, следует переписать init()
создать таблицу базы данных。Настройка по умолчанию。противModel
иTransientModel
Автоматически устанавливаетсядляFalse
,противAbstractModel
Автоматически устанавливаетсядляFalse
。Сносно继承AbstractModel
создать тот, который не требует каких-либо таблиц данных Модель
_log_access
Будет ли ORM автоматически генерировать и обновлять Access Log fields。по умолчанию_auto
изценить。
_table= None
Модельверноотвечатьиз数据库поверхностьизимя。если_auto
настраиватьдляTrue
из话。
_sequence= None
Последовательность SQL для поля идентификатора
_sql_constraints= []
ограничения SQL,Формат:[(name, sql_def, message)]
_register= True
registry visibility
_abstract= True
Будь то абстрактная модель
_transient= False
лидляtransientМодель
_name= None
Название модели (начинается с точкаточка式имяиз模块имя,напримерestate.users
)
_description= None
Описание модуля, нецелое имя
_inherit= None
унаследованныйPythonМодель:Нужно наследовать Модельизимя(_name
свойствоценить)илисписок имен(list
тип)
_inherits= {}
(Не совсем понимаю)
dictionary {‘parent_model’: ‘m2o_field’} mapping the _name of the parent business objects to the names of the corresponding foreign key fields to use:
_inherits = {
'a.model': 'a_field_id',
'b.model': 'b_field_id'
}
implements composition-based inheritance: the new model exposes all the fields of the inherited models but stores none of them: the values themselves remain stored on the linked record.
предупреждать
if multiple fields with the same name are defined in the _inherits
-ed models, the inherited field will correspond to the last one (in the inherits list order).
_rec_name= None
Поле для разметки записей,по умолчаниюценить:name
_order= 'id'
Поле сортировки по умолчанию, используемое для результатов поиска
_check_company_auto= False
осуществлятьwrite
иcreate
, обладать check_company=True
свойствоизассоциация Полевызов_check_company
чтобы обеспечить целостность компании
_parent_name= 'parent_id'
Поле «many2one», используемое в качестве родительского поля
_parent_store= False
настраиватьдляTrue
рассчитатьparent_path
Поле。иparent_path
вместе,Настройте индексное хранилище для древовидной структуры записей.,так чтоиспользоватьchild_of
иparent_of
Операторы домена применяются к текущему Модельиз Записывать进行更快източказапрос слоя
_date_name= 'date'
Поля, используемые для просмотра календаря по умолчанию
_fold_name= 'fold'
Поле, используемое для определения свернутых групп в представлении Канбан.
odoo.models.AbstractModel
[исходный код]
odoo.models.BaseModel
из别имя
class odoo.models.Model
[исходный код]
Основной родительский класс для обычных моделей персистентности базы данных Odoo.
Создайте модели Odoo, унаследовав этот класс:
class user(Model):
...
Экземпляр класса будет создан один раз для каждой базы данных, в которой установлен этот модуль класса.
_auto= True
Следует ли создавать таблицу базы данных. Если установлено значение False
, следует переписать init()
создать таблицу базы данных。Настройка по умолчанию。противModel
иTransientModel
Автоматически устанавливаетсядляFalse
,противAbstractModel
Автоматически устанавливаетсядляFalse
。Сносно继承AbstractModel
создать тот, который не требует каких-либо таблиц данных Модель
_abstract= False
Будь то абстрактная модель
_transient= False
лидляtransientМодель
class odoo.models.TransientModel
[исходный код]
Родительская модель для временных записей, предназначенная для временного хранения и периодической очистки.
TransientModel
具иметь简化издоступ权限管理,Все пользователи могут создаватьновый записывать и получать к ним доступ только записи созданы。Суперпользователь имеет неограниченный доступ ко всемTransientModel
Записывать。
_auto= True
Следует ли создавать таблицу базы данных. Если установлено значение False
, следует переписать init()
создать таблицу базы данных。Настройка по умолчанию。противModel
иTransientModel
Автоматически устанавливаетсядляFalse
,противAbstractModel
Автоматически устанавливаетсядляFalse
。Сносно继承AbstractModel
создать тот, который не требует каких-либо таблиц данных Модель
_abstract= False
Будь то абстрактная модель
_transient= False
лидляtransientМодель
class odoo.fields.Field[исходный код]
Поля имеют следующие свойства
string (str) – Метка поля, которую видит пользователь; если она не установлена, ORM будет использовать первую букву имени поля в классе, которая будет заглавной.
help (str) – Панель подсказок поля, которую видит пользователь (после установки этого атрибута при наведении курсора мыши на метку поля автоматически появляется панель подсказок для отображения текстового содержимого атрибута).
invisible – Полели可见。по умолчаниюдляFalse
,Видимый
readonly (bool) – Доступно ли поле только для чтения в пользовательском интерфейсе, значение по умолчанию. False
,Работает только в пользовательском интерфейсе
required (bool) – Требуется ли поле в пользовательском интерфейсе, по умолчанию False
。Это делается на уровне базы данныхдля Столбец добавленNOT NULL
ограничения для достижения
index (bool) – Добавлять ли индекс в поле. Примечание. Это не работает для несохраненных и виртуальных полей. значение по умолчанию: False
default (значение или вызываемый объект) – Установите значение поля по умолчанию. Это может быть статическое значение или функция, которая принимает набор результатов в качестве входного параметра и возвращает определенное значение. использовать default=None
отбрось это Полеизпо умолчаниюценить。
states (dict) –Воляstate
ценитьсопоставлено сUIсвойство-ценитьверносписокизсловарь映射,Проще говоря, он позволяет создавать пользовательский интерфейс на основеstate
Полеизценить Приходить动态настраиватьверноотвечать ПолеизUIсвойство,поэтому,Для этого требуется наличиеstate
Полеи в представлениииспользовать(即使да隐藏из),state
свойствоизимядасуществоватьodoo硬编码и Нет允许修改из,可用свойствоиметь: readonly
, required
, invisible
。Напримерstates={'done':[('readonly',True)]}
,означает, когдаstate
ценитьдляdone
час,Воляпользовательский интерфейсstates
расположение Полесуществоватьнастраиватьдлятолько чтение (только для уровня пользовательского интерфейса)
Примеры использования:
state = fields.Selection([
('draft', 'To Submit'),
('cancel', 'Cancelled'),
('confirm', 'To Approve'),
('refuse', 'Refused'),
('validate1', 'Second Approval'),
('validate', 'Approved')
], string='Status', readonly=True, copy=False, default='confirm')
date_from = fields.Datetime(
'Start Date', readonly=True, index=True, copy=False,
states={'draft': [('readonly', False)], 'confirm': [('readonly', False)]})
groups (str) – Значения представляют собой группы XML, разделенные запятыми. список идентификаторов,нравитьсяgroups='base.group_user,base.group_system'
,Доступ к Поле может быть ограничен только для пользователей определенной группы.
company_dependent (bool) –
Зависит ли Полеценить от текущей компании?,еслинастраиватьдляTrue
,означает полагаться на текущую компанию,Это является обязательным условием компании «Полеценитьи». Функция этого атрибута – сделать такого же Поле, может основываться не на таком та же компания, склад не такой жеценить, если предположить, что пользователь принадлежит более чем к одной компании, он не такой же公司из职务也Нетодин样,此час就可кнастраивать ДолженсвойстводляTrue
。
Долженценитьне хранится в текущем Модельв таблице。он регистрируетсядляir.property
,也就да说этоизценитьхранится вir_property
в таблице,Получите цену поля, запросив таблицу.
copy (bool) – При дублировании записей копируется ли значение поля (при использовании ORM copy()
методкопироватьи генерироватьновый рекордчас,Неткопировать Должен Полеизценить)。 (Для обычных полей значение по умолчанию: True
,противone2many
и Расчетное поле,包括свойство Поле(property fields
,Регистрация личного взаимопониманияir.property
из Поле)исвязь Поле,по умолчаниюценитьдляFalse
store (bool) – Сохраняется ли Поле в базе данных для Расчетного поле,по умолчаниюценитьдляFalse
,другой Полепо умолчаниюдляTrue
group_operator (str) –
При группировке по текущему полю для read_group()
используемая агрегатная функция
Поддерживаемые агрегатные функции:
array_agg
: ценить,Включить пустую цену,объединить в массивcount
: Количество записейcount_distinct
: Не повторяется записейbool_and
: для истинно, если все ценить истинно, в противном случае для ложноbool_or
: если至少иметьодинценитьдлянастоящий,нодлянастоящий,В противном случаедля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])
bool
из封装
Базовое строковое поле, ограниченное по длине, обычно отображается на клиенте как однострочная строка.
параметр:
True
)。пожалуйста Уведомление,черносливдействоватьтолько Web клиентское приложение.– Включить перевод слова «Полеценить», используемого для;
translate=TrueОбщий перевод Полеценить;
translateтакже может быть вызываемым, что делает
translate(callback,value)проходитьиспользовать
callback(term)искать перевод терминов для перевода
value`
float
из封装
精度数字由Необязательныйизdigitals
свойство Давать出。
параметр
digits (tuple
(int
, int
), илиstr
) – одинкортеж(total, decimal)
или ЦитироватьDecimalPrecision
записанная строка
digits=(8,2) Представляет в общей сложности 8 цифр, а десятичная точка занимает 2 цифры.
Класс Float предоставляет для этого несколько статических методов:
round()
к Давать定精度верно浮точкаценитьвыполнить округление。is_zero()
检查浮точкаценитьсуществовать Давать定精度下лиравныйноль。compare()
в соответствии с Давать定精度Сравниватьдва浮точкаценить。
пример:
fields.Float.round(self.product_uom_qty, precision_rounding=self.product_uom_id.rounding)
fields.Float.is_zero(self.product_uom_qty, precision_rounding=self.product_uom_id.rounding)
field.Float.compare(self.product_uom_qty, self.qty_done, precision_rounding=self.product_uom_id.rounding)
Сравнивать助手出于历史目изиспользовать__cmp_
Семантика,поэтомуиспользовать此助手из正确惯用Способследующее:
Если результат==0, первое и второе числа с плавающей запятой равны. Если результат<0, первое число с плавающей запятой равно меньше. чем Второй,еслиresult>0,第один浮动точка数больше, чем Второе число с плавающей запятой
int
из封装
Инкапсулировать двоичный контент (например, файл).
параметр:
– Есть ли магазины Поле для
ir_attachmentИли столбец таблицы модели (по умолчанию для:
True`, то есть сохраняется прежнее.Инкапсуляция содержимого html-кода
параметр:немного
Картинная упаковка,РасширятьBinary
Если размер изображения больше, чемкартина素изmax_width/max_height
предел,Затем размер изображения подстраивается под этот предел, сохраняя соотношение сторон Воля.
параметр:
0
,без ограничений)0
,без ограничений)True
。самое большое изображениеточкаразрешениепожалуйста参阅odoo.tools.image.ImageProcess
(по умолчаниюценить:50e6
)。
параметр
если не указано max_width
/max_height
илинастраиватьдля0,иverify_resolution
дляFalse
,Поле контент не будет проверен,此часотвечать ДолжениспользоватьBinary
Поле。
инкапсулирует данноеres_currency
поверхность示из浮точкаценить。
Десятичная точностьи Символ валюты взят изcurrency_field
свойство。
параметр:
res_currency
изMany2one
Полеимя(по умолчанию: 'currency_id'
)Инкапсулирует взаимоисключающий выбор между различными значениями.
проиллюстрировать:Selection
Полеиз Необязательныйценить,хранится вpublic.ir_model_fields_selection
в таблице,проходитьfield_id
Полепроходитьpublic.ir_model_fields
таблица продолжить
-- QuerySelectionПолеID
SELECT id FROM public.ir_model_fields
where model = 'stock.quality' and name='state'
-- Проверить выбор Поле Необязательноценить
select * from public.ir_model_fields_selection where field_id = 13028; -- 13028дляSelectionПолеID
параметр:
selection (list(tuple(str, str)) или вызываемый объект или str)) – обозначение Полеиз Необязательныйценить。Чтоценитьдля Включать2кортежизсписок,иливозвращаться прежним модельным методом,или Имя метода
selection_add (list(tuple(str, str)) –
В случае переписывания Поле,поставлятьselection
из Расширять。этодаодин Включать二кортеж(value, label)
илиодинкортеж(value,)
изсписок,в,одинкортежсерединаизvalue
Должен сделатьдляvalue
Появиться вselection
списоксерединаизкортежсередина。новыйценитьзаказ на размещениеиоригинальныйselection
серединакортеж Следите за порядком:
selection = [('a', 'A'), ('b', 'B')]
selection_add = [('c', 'C'), ('b',)]
> result = [('a', 'A'), ('c', 'C'), ('b', 'B')]
ondelete –
длясselection_add
из任何重写Полепоставлять回退机制。этотдаодин Воляselection_add
серединаизкаждый选项сопоставлено с回退действоватьизdict。
Этот запасной вариантдействовать Воляприложение于Чтоselection_add
选项сопоставлено с Должендействоватьиз所иметь Записывать。
Это может быть любое из следующих действий:
set null
По умолчанию,具иметь此选项из所иметь Записыватьизвыбиратьценить Все ВолянастраиватьдляFalse。cascade
–具иметь此选项из所иметь Записывать Воляи选项本身Вместеудалить.set default
-具иметь此选项из所иметь Записывать Все Волянастраиватьдля Полеопределениеизпо умолчаниюценить<callable>
-один可вызовобъект,Его первый и единственный параметр Воля — это набор записей, содержащий указанный параметр выбора.,для индивидуальной обработкиselection
свойствовыбиратьда强制сексиз,Если это неrelated
или Расширятьиз Поле
похожийChar
,для более длинного контента,нет размера,обычно отображаетсядлянесколько строктексткоробка。
параметр:
translate (bool или вызываемый объект) – такой же Char
При присвоении значения Date
/Datetime
поле, допустимы следующие варианты:
date
или datetime
объект.Date
ПолеиспользоватьYYYY-MM-DD
Datetime
Полеиспользовать YYYY-MM-DD HH:MM:SS
False
или None
.Date
иDatetime
Классы полей имеют следующие вспомогательные функции для попыток преобразования в совместимые типы:
to_date()
Конвертировать дляdatetime.date
to_datetime()
Конвертировать для datetime.datetime
.Пример
Анализ даты/даты и времени из внешнего источника:
fields.Date.to_date(self._context.get('date_from'))
Date
/Datetime
Сравните лучшие практики:
Date
Полеможет толькоиdateобъект СравниватьDatetime
Полеможет толькоиdatetimeобъект СравниватьDatetime
Поля хранятся в базе данных как метки времени без часового пояса и в часовом поясе UTC. Это делает базу данных Odoo независимой от часового пояса системы хост-сервера. Преобразование часового пояса полностью управляется клиентом.
Common operations with dates and datetimes such as addition, subtraction or fetching the start/end of a period are exposed through both Date
and Datetime
. These helpers are also available by importing odoo.tools.date_utils
.
Python date
объектиз封装
static add(value, *args, **kwargs)
возвращаться value
и relativedelta
Изи
date
илиdatetime
args – перешел кrelativedelta
из Расположениепараметр
kwargs – перешел кrelativedelta
из关键词параметр
Пример:
from odoo.fields import Date
print(Date.add(datetime.now(), years=1)) # Вывод выглядит так: 2024-01-03
# общийпараметр:
# years, months, days, leapdays, weeks, hours, minutes, seconds, microseconds
static subtract(value, *args, **kwargs)
[исходный код]
возвращаться value
и relativedelta
Из差
date
илиdatetime
args – перешел к relativedelta
Расположениепараметр
kwargs – перешел к relativedelta
из关键词параметр
date/datetime
результатобъект
static context_today(record, timestamp=None)
[исходный код]
в соответствии с客户端час区к适合date
Полеиз Форматвозвращатьсятекущийдата
аннотация Этот метод можно использовать для расчета значения по умолчанию.
datetime
) – 替代текущийдатачас间(datetime)из Необязательныйизdatetime
объект
date
static end_of(value, granularity)
[исходный код]
Получить конец периода времени по дате или дате и времени
date
илиdatetime
granularity – Тип периода времени, представленный строкой, может бытьyear
, quarter
, month
, week
, day
илиhour
。
date/datetime
объект
Пример:
print(datetime.now()) # 2023-01-03 10:12:32.332208
print(Date.end_of(datetime.now(), 'year')) # Вывод выглядит так: 31 декабря 2023 г. 23:59:59.999999
print(Date.end_of(datetime.now(), 'month')) # Вывод выглядит так: 2023-01-31. 23:59:59.999999
static start_of(value, granularity)
[исходный код]
Получить начало периода времени из даты или даты и времени.
date
илиdatetime
granularity – Тип периода времени, представленный строкой, может бытьyear
, quarter
, month
, week
, day
илиhour
。
date/datetime
объект
Пример:
print(datetime.now()) # 2023-01-03 10:18:57.071276
print(Date.start_of(datetime.now(), 'year')) # Вывод выглядит так: 2023-01-01. 00:00:00
print(Date.start_of(datetime.now(), 'month')) # Вывод выглядит так: 2023-01-01. 00:00:00
print(Date.start_of(datetime.now(), 'hour')) # Вывод выглядит так: 2023-01-03 10:00:00
static to_date(value)
[исходный код]
попробуй конвертировать value
для date
объект
предупреждать еслиvalueдля
datetime
объект,это Воляодеяло Конвертировать дляdate
объект,и所иметьдатачас间特定信息(HMS, TZ, ...) будет потерян.
value
изобъект
date
типилиNone
static to_string(value)
[исходный код]
Воля date
илиdatetime
объект для строки
value
нить. если value
дляdatetime
тип,Автоматически сбрасывать часы,точка,Второй,Информация о часовом поясе.Пример:
print(Date.to_string(datetime.now())) # Вывод выглядит так: 2023-01-03
static today(*args)
[исходный код]
возвращатьсятекущийдата
Пример:
print(Date.today()) # Формат следующий: 03.01.2023.
Python datetime
объектиз封装
static context_timestamp(record, timestamp)
[исходный код]
возвращаться Конвертировать для客户端час区из Давать定час间戳。
аннотация Этот метод не используется в качестве начальной настройки ценообразования по умолчанию.,потому чтодля
datetime
Полесуществовать客户端显示час会自动转换。дляпо умолчаниюценить,отвечатьиспользоватьnow()
datetime
ценить (UTC
поверхность示из)
datetime
datetime
static add(value, *args, **kwargs)
[исходный код]
ссылкаDate.add
static subtract(value, *args, **kwargs)
[исходный код]
ссылкаDate.subtract
static end_of(value, granularity)
[исходный код]
ссылкаDate.end_of
static start_of(value, granularity)
[исходный код]
ссылкаDate.start_of
static to_string(value)
[исходный код]
ссылкаDate.to_string
static today(args)
[исходный код]
возвращатьсяв тот день,полночь (00:00:00)
Пример:
from odoo.fields import Datetime
print(Datetime.today()) # Вывод выглядит так: 2023-01-03 00:00:00
print(Datetime.now()) # Вывод текущего времени 2023-01-03 12:33:00
static to_datetime(value)
[исходный код]
ВоляORM value
转для datetime
ценить
value
изобъект
datetime
илиNone
class odoo.fields.Many2one
[исходный код]Many2one
Полеизценитьэто размердля0(无Записывать)или1(один个Записывать)из Записывать集。
параметр:
comodel_name
является обязательнымпараметр,Если только это не связано или Расширять Поле (не совсем понимаю,оригинальный:name of the target model Mandatory
except for related or extended fields)'set null'
, 'restrict'
, 'cascade'
JOIN
(по умолчанию: False
)True
к标记Сноснотекущий Модельцель доступа Модельиз Поле(верноотвечать_inherits
)_check_company()
середина校验из Поле。в зависимости от Полесвойство,Добавить домен компании по умолчаниюclass odoo.fields.One2many
[исходный код]One2many
Полеизценитьдля comodel_name
середина所иметь满足条件из Записыватьизрезультат集,И цель Модельсерединаиз inverse_name
Это эквивалентно текущей записи.
параметр:
Many2one
Полеимя,По данным записи обратного запроса ПолеJOIN
(по умолчанию: False
)comodel_name
иinverse_name
Параметр является обязательным, если он не связан с или Расширять Поле.
class odoo.fields.Many2many
[исходный код]Many2many
Полеизценитьдляодинрезультат集。
параметр:
relation
в таблице Цитировать"Эти"Записыватьиз列имя,Необязательныйпараметрrelation
в таблице Цитировать"Вон те"Записыватьиз列имя,Необязательныйпараметрrelation
, column1
иcolumn2
параметр Необязательный。 Если не указано, оно генерируется автоматически на основе названия модели, и предоставленное имя не такое. жеизmodel_name
иcomodel_name
。
Уведомление,ORM не поддерживает данную модель,использоватьтакой же样изcomodel
,создавать Несколько省немного Понятноrelation
параметриз Поле,потому чтодля Эти Поле Воляиспользовать Взаимнотакой жеизповерхность。ORMвторой блокMany2many
Полеиспользовать Взаимнотакой жеизrelation
параметр,пока не:
comodel
и显示обозначениеrelation
параметр,в противном случае_auto = False
из Модельпараметр:
_check_company()
середина校验из Поле。в зависимости от Полесвойство,Добавить условие компании по умолчаниюУведомление:odooНет会существоватьтекущий Модельверноотвечатьв таблицедляOne2many
,Many2many
типизсвойство建立верноотвечатьизповерхность Поле,Но это будетдляMany2one
типизсвойство建立верноотвечатьповерхность Поле,противMany2many
типизсвойство,Odoo создаст вспомогательную таблицу,поверхностьимяпо умолчанию Форматдляmodel1_table_name_model2_table_name_rel
,В таблице есть два столбца,столбецдлятекущий Модельпервичный ключ таблицыID(model1_table_name_id
),столбецдлясвязь Полеассоциация Модельповерхностьизпервичный ключID(model2_table_name_id
),такпроходить两поверхность ЗаписыватьID就可к查询所需Записывать Понятно
class odoo.fields.Reference
[исходный код]
Поля псевдоотношений(数据库середина没иметьFK)。Должен Полеценитьхранилищедля数据库середина遵循модель"res_model,res_id"
изхарактернить。
class odoo.fields.Many2oneReference
[исходный код]
Должен Полеизценитьхранилищедля数据库серединаизодинцелое число。иodoo.fields.Reference
Поле Взаимно反,должно быть вChar
тип Полесерединаобозначение Модель,в,Должен Полеизимядолжно быть втекущийMany2oneReference
Полесерединаизmodel_field
свойствосерединаобозначение
параметр:model_field (str) – Сохраняет название модели.
Можно использовать 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)]
в праве Модель进行действительный搜索Из前处理domainчасвызов Должен搜索метод。этодолженвозвращатьсяи条件field operator value
等效изdomain
Расчетное полепо умолчаниюценить。дляразрешено Расчетное поле进行настраивать,использовать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
предупреждать Хотя можно использовать фазу такой на нескольких Поле. жеизвычислитьметод,但Нет建议верно
reverse
методиспользовать Взаимнотакой тот же метод. существоватьreverse
извычислить过程середина,所иметьиспользоватьописалinverseиз Поле Все受到保护,Это значит даже если их ценить нет в кеше,Их также невозможно вычислить. Если вы посетили любой из этих Поле,и его ценить нет в кеше,ORMВоля简одиниздля Эти Полевозвращатьсяпо умолчаниюценитьFalse
。этот意味着Этиinverse
Полеизценить(курокinverse
методизценитькроме)可能Нет会Давать出正确изценить,это может сломатьсяinverse
методиз预期行для
Расчетное полеизодин种特殊情况даСвязанный(актерское мастерство)Поле,этопоставлятьтекущий Записыватьначальство子Полеизценить。это们дапроходитьнастраиватьrelated
параметр Приходитьопределениеиз,То же, что и обычное Расчетное поле,Они могут хранить:
nickname = fields.Char(related='user_id.partner_id.name', store=True)
related
Полеизценитьдапроходить遍历один系列связь Полеи прочитайте полученный доступ Модельначальствоиз Поле Приходить Давать出из。要遍历из Полеиз完整序列由related
свойствообозначение
Если некоторые свойства Поле не переопределены,но会自动从源Полесерединакопировать Этисвойство:string
、help
、required
(толькокогда序列серединаиз所иметь Поле Вседа必需изчас)、groups
、digits
、size
、translate
、cleaning”、“selection
、comodel_name
、domain
иcontext
。所иметь无Семантикасвойство Все从源Полекопировать。
По умолчанию, связанное поле:
картина Расчетное поле туда, добавь store=True
кхранилищеrelated
Поле。когда Что依赖одеяло修改час,会自动重новыйвычислитьrelated
Поле。
Советы
если Нет希望существовать任何依赖项更改час重новыйвычислитьrelated
Поле,Затем вы можете указать точные зависимости Поле:
nickname = fields.Char(
related='partner_id.name', store=True,зависит=['partner_id'])
# Псевдоним будет пересчитан только при изменении Partner_id,Он не будет пересчитываться при изменении имени партнера.
предупреждать
Нет可ксуществоватьrelated
Поле依赖项середина Включать Many2many
или One2many
Поле
related
Может использоваться для ссылки на другую модель. One2many
илиMany2many
Поле,前提дапроходитьтекущий МодельизодинMany2one
связь Приходить实现из。 One2many
иMany2many
Не поддерживается и не может правильно агрегировать результаты:
m2o_id = fields.Many2one()
m2m_ids = fields.Many2many()
o2m_ids = fields.One2many()
# Supported
d_ids = fields.Many2many(related="m2o_id.m2m_ids")
e_ids = fields.One2many(related="m2o_id.o2m_ids")
# Won't work: use a custom Many2many computed field instead
f_ids = fields.Many2many(related="m2m_ids.m2m_ids")
g_ids = fields.One2many(related="o2m_ids.o2m_ids")
odoo.fields.id
IDПоле
Если текущая длина набора записей равна 1, появляется идентификатор уникальной записи в наборе записей. В противном случае выдать ошибку
если启用_log_access
,Автоматически устанавливать и обновлять эти Поле. Когда эти предметы не используются,Отключите его, чтобы предотвратить создание этих обновлений в таблице.
по умолчанию _log_access
одеялонастраиватьдля _auto
изценить。
odoo.fields.create_date
создавать Записыватьчасхранилищесоздаватьчас间,Datetime
тип
odoo.fields.create_uid
Хранит создателя записи, Many2one
to a res.users
odoo.fields.write_date
хранилище Записывать最后更новыйчас间,Datetime
тип
odoo.fields.write_uid
Сохраняет человека, который последним обновил запись, Many2one
to a res.users
.
предупреждать
должно быть правodoo.models.TransientModel
Модельвключать_log_access
В дополнение к автоматическому Поле,Есть также некоторые имена Поле, которые зарезервированы предопределенной строкой для. Когда нужны связанные строки для,отвечатьсуществовать Модельначальствоопределениеэто们:
odoo.fields.name
_rec_name
изпо умолчаниюценить,используется при необходимостипредставлятьсекс“имя”изначальство下文середина显示Записывать。odoo.fields.Char
тип
odoo.fields.active
切换Записыватьиз全局可见секс,еслиactive
настраиватьдляFalse
,но Записыватьсуществовать大много数搜索исписоксередина Нет可见。odoo.fields.Boolean
тип
odoo.fields.state
объектиз声明周期阶段,дляfields.[Selection
из states
Использование атрибута
odoo.fields.parent_id
_parent_name
изпо умолчаниюценить,Используется для организации записей в древовидной структуре.,и вdomainсередина启用child_of
иparent_of
оператор。Many2one
Поле。
odoo.fields.parent_path
когда_parent_store
настраиватьдляTrue
час,用于хранилище反映[_parent_name
]树结构изценить,и оптимизировать поискdomainсерединаизchild_of
иparent_of
оператор。должениспользоватьindex=True
Высказывание может быть правильнымдействовать。odoo.fields.Char
тип
odoo.fields.company_id
用于OdooМногопрофильная линиядляиз主Полеимя。для:meth:~Odoo.models._check_company
用于检查Несколько компанийодин致секс。определение Записывать Есть公司Из间共享(没иметьценить)还датолько Давать定公司из用户доступ。Many2one
:тип: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), ...
Recordset предоставляет «Активный Record” интерфейс:Модель Поле Можно сделать напрямуюдля Записыватьизсвойство直接читатьиписать。
аннотация
При доступе к нереляционному Поле в наборе записей, состоящем из потенциально нескольких записей.,использоватьmapped()
,Функция получила список:
total_qty = sum(self.mapped('qty')) # mappedвозвращаться списком вида [2,4,5]
Полеценить также можно получить как словарную статью. Установка цены Поле запускает обновление базы данных:
>>> record.name
Example Name
>>> record.company_id.name
Company Name
>>> record.name = "Bob"
>>> field = "name"
>>> record[field]
Bob
предупреждать
Many2one
,One2many
,Many2many
),Всегда устанавливается рекорд,Если Поле не установлено,Затем появляется пустой набор записей.Odoo для Поле поддерживает кеш,так,Не при каждом доступе со стороны Поле будет выполняться запрос к базе данных.
Следующий пример запрашивает базу данных только для первого оператора:
record.name # Первый доступ получает ценить из базы данных
record.name # Второе посещение получает ценить из кеша
для того, чтобы не читать записи по одному Поле за раз,Odoo будет предварительно выбирать записи в соответствии с некоторыми эвристическими правилами.,чтобы получить хорошую производительность. Однажды Поле необходимо прочитать по данной записи,ORM фактически прочитает это Поле в большем наборе записей.,и Волявозвращатьсяизценитьхранится в缓存серединакдля后续использовать。предварительная выборкаиз Записывать集в целомдапроходить迭代获得Записыватьиз Записывать集。также,Все простые хранилища Поле (логическое ценить, целое число, плавающее ценить, символ, текст, дата, дата-время, выбор, много2один) извлекаются и соответствуют столбцам таблицы модели;,и втакой Эффективное получение за один запрос.
Рассмотрим следующий пример,в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
Модуль Odoo API определяет модификаторы методов среды Odoo.
odoo.api.autovacuum(method)
[исходный код]
Украсьте метод так, чтобы он использовался ежедневным пылесосом. cronОперация(Модельir.autovacuum
)вызов。этотв целом用于垃圾收集Из类из Нетнуждаться特定cronОперацияиз任务
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.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)
[исходный код]
Модификатор, определяющий контекстные зависимости для несохраняемых «вычислительных» методов. Каждый параметр является ключом в контекстном словаре:
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)
Все зависимости должны быть хешируемыми. Следующие ключи имеют специальную поддержку:
company
(ценитьили текущий идентификатор компании в контексте),uid
(текущий идентификатор пользователя и тег суперпользователя),active_test
(env.context
илиfield.context
серединаизценить).odoo.api.model(method)
[исходный код]
Изменение метода стиля записи,вself
даодин空Записывать集,но его содержание не имеет значения,Только связанные с моделью,Понятно, что для не создаст объект модели, соответствующий записи базы данных. для работы на уровне модели необходимо добавить этот модификатор,Эквивалент статической функции класса
@api.model
def method(self, args):
...
odoo.api.model_create_multi(method)
[исходный код]
Измените список словарей для метода параметра и создайте несколько записей. Метод можно вызвать только со словарем и списком словарей:
record = model.create(vals)
records = model.create([vals, ...])
odoo.api.onchange(*args)
[исходный код]
Получается Декоратор, который изменяет метод onchange данного Поле.
В виде формы, где отображается Поле,При изменении данного Поле,Воля вызывает этот метод. Этот метод вызывается для фиктивной записи, содержащей значение цены, присутствующее в форме. Запись на Поле грантценить Воля появилась автоматическим клиентом.
Каждый параметр должен быть именем поля:
@api.onchange('partner_id')
def _onchange_partner(self):
self.message = "Dear %s" % (self.partner_id.name or "")
return {
'warning': {'title': "Warning", 'message': "What is this?", 'type': '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
实例изметодвозвращатьсяодин修饰器
'self'
downgrade – один用于转换record-styleизvalue
для传统风格输出из函数downgrade(self, value, *args, **kwargs)
upgrade – один用于转换传统风格(traditional-style)изvalue
дляrecord-styleиз输出из函数upgrade(self, value, *args, **kwargs)
параметр self
, *args
и**kwargs
кrecord-styleСпособперешел метод
Вывод метода модификатора Воля адаптирует стиль 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)
Обратите внимание, что модифицированный метод должен удовлетворять этому контракту.
Эти修饰器да自动унаследованный:重写одеяло修饰из现иметьметодизметод Воляодеяло Взаимнотакой жеиз@return(модель) модификация
Environment
Хранит различные контекстные данные, используемые ORM: просмотр базы данных (для запросов к базе данных), текущий пользователь (используется для проверки прав доступа) и текущий контекст (хранит произвольные метаданные). среда также хранит кеш.
Все наборы записей имеют среду,это неизменно,Можно использоватьenv
доступ,и предоставляет доступ к:
user
)cr
)su
)context
)>>> records.env
<Environment object ...>
>>> records.env.user
res.user(3)
>>> records.env.cr
<Cursor object ...)
>>> self.env.context # появились словарные данные, эквивалентные self._context
{'lang': 'en_US', 'tz': 'Europe/Brussels'}
>>> self._context
{'lang': 'en_US', 'tz': 'Europe/Brussels'}
При создании набора записей из другого набора записей,Воля унаследовал окружающую среду. среду можно использовать для получения пустых наборов записей из других моделей.,и查询Должен Модель:
>>> 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
)серединаобозначение, возвращатьсятекущий Основная компания пользователя (если not specified in the context(allowed_company_ids
), fallback on current user companies)
allowed_company_ids
Содержание контекстного ключа
self.user.company_id
)
res.company
предупреждать
Никакой проверки работоспособности приложения в режиме sudo! В режиме sudo пользователь может получить доступ к любой компании, даже не к той, которую ему разрешено делать.
Это позволяет инициировать изменения внутри компании, даже если текущий пользователь не имеет доступа к целевой компании.
Environment.companies
появляется набор записей компании, доступный пользователю.
если не в контексте (allowed_company_ids
)серединаобозначение, возвращатьсятекущий Основная компания пользователя (если not specified in the context(allowed_company_ids
), fallback on current user companies)
allowed_company_ids
Содержание контекстного ключа
self.user.company_id
)
res.company
предупреждать
Никакой проверки работоспособности приложения в режиме sudo! В режиме sudo пользователь может получить доступ к любой компании, даже не к той, которую ему разрешено делать.
Это позволяет инициировать изменения внутри компании, даже если текущий пользователь не имеет доступа к целевой компании.
Model.with_context([context][, **overrides])
-> records[исходный код]
Будет новая версия этого набора записей, прикрепленная к контексту Расширять.
Расширятьначальство下文дапоставлятьиз合и Понятноoverrides
изcontext
,илида合и Понятноoverrides
текущийcontext
# 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_company(company)
[исходный код]
появится новая версия этого набора записей с измененным контекстом.,так:
result.env.company = company
result.env.companies = self.env.companies | company
res_company
или int) – Главная компания новой среды
предупреждать
когдатекущий пользовательиспользовать未经授权из公司час,Если нет доступа к компании в sudoedсреда,но可能会курокAccessError
Model.with_env(env)
[исходный код]
становится прикрепленным к новой версии этого набора записей, предоставленной средой.
Environment
) –
предупреждать
Новая среда Воля не будет использовать кэш данных текущей среды.,поэтому稍后из数据доступ可能会существовать从数据库重новыйполучать数据час产生额外из延迟。возвращатьсяиз Записывать集具иметьиself
Взаимнотакой же предварительная выборка объекта.
Model.sudo([flag=True])
[исходный код]
в соответствии сflag
,станет включать или отключать новую версию этого набора записей для модели суперпользователя. Модель суперпользователя не изменится текущего пользователя,Просто обойдите проверку прав доступа.
предупреждать
использоватьsudo
可能会导致数据доступ跨越Записывать规ноиз边界,Может возникнуть путаница относительно того, какие записи следует поместить в карантин (например,,Несколько компанийсредасередина Приходить自Неттакой те же записи компании).
Это может привести к неинтуитивным результатам при использовании методов выбора записи среди нескольких записей, таких как получение компании по умолчанию или выбор спецификации.
аннотация
Потому что для необходимо переоценить правила ведения журнала и контроль доступа.,Таким образом, новый набор записей Воля не будет использовать кэш данных текущей среды.,поэтомук后из数据доступ可能会существовать从数据库重новыйполучатьчас产生额外из延迟。возвращатьсяиз Записывать集具иметьиself
Взаимнотакой же предварительная выборка объекта.
среданачальствоизcr
свойстводатекущий数据库事务изкурсор,Разрешить прямой доступосуществлятьSQL,Будь тодля难киспользоватьORMповерхность达из查询(Напримерсложныйjoin),или по соображениям производительности
self.env.cr.execute("some_sql", params)
потому что Модельиспользовать Взаимнотакой жеизкурсор,ииEnvironment
Сохраняйте различные тайники,поэтомукогдасуществовать原始SQLсередина更改数据库час,Эти кеши должны быть признаны недействительными.,в противном случае Модельиз进один步использовать可能会变得Нет连贯。существоватьSQLсерединаиспользоватьCREATE
、UPDATE
илиDELETE
,但НетиспользоватьSELECT
(только чтения при выборке базы данных) кэш необходимо очистить.
аннотация
Можно использовать invalidate_cache()
осуществлять缓存из清理
Model.invalidate_cache(fnames=None, ids=None)
[исходный код]
修改某些Записывать后,使Записывать缓存无效。еслиfnames
иids
ВседляNone
,но清除整个缓存。
параметр:
fnames–Модифицированный Полеизсписок,None
поверхность示所иметь Поле
ids–修改из ЗаписыватьIDизсписок,None
поверхность示所иметь Записывать
предупреждать
Выполнение необработанного SQL обходит ORM, тем самым обходя правила безопасности Odoo. Обязательно очищайте свои запросы при использовании пользовательского ввода, а если вам действительно не нужно использовать запросы SQL, используйте утилиту ORM.
Model.create(vals_list)
→ records[исходный код]
для Модельсоздаватьновый рекорд
использоватьсловарьсписокvals_list
серединаизценитьисходный化новый рекорд,если необходимо,использоватьdefault_get()
серединаизценить
[{'field_name':field_value,…},…]
дляобратная совместимость,vals_list
может бытьодинсловарь。этоодеяло视дляодин个список[vals]
,ивозвращатьсяодин条Записывать。иметь关详细信息пожалуйста参见write()
ValidationError – Если пользователь пытается ввести неверную цену, которая находится за пределами выбора UserError–если Волясуществоватьобъект层次结构серединасоздаватьцикл,Результат действия (например, воляобъект устанавливает свой собственный родительский объект)
Model.copy(default=None)
[исходный код]
использоватьпо умолчаниюценить更новый拷贝из Записыватьself
{'field_name': overridden_value, ...}
Model.default_get(fields_list)
→ default_values[исходный код]
возвращатьсяfields_list
середина Полеизпо умолчаниюценить。по умолчаниюценить由начальство下文、用户по умолчаниюценитьи Модельрешай сам
аннотация
Незапрошенная цена по умолчанию не учитывается.,Нетнуждатьсядляимя Нетсуществоватьfields_list
серединаиз Полевозвращатьсяценить。
Model.name_create(name)
→ record[исходный код]
проходитьвызовcreate()
создаватьновый рекорд,вызовчасcreate()
час只поставлятьодинпараметрценить:новый Отображаемое имя записи.
новый рекорд Воляиспользовать Применимый于此Модельиз任何по умолчаниюценитьисходный化,илипроходитьначальство下文поставлять。create()
изв целом行для Применимый
name_get()
попарноценить Model.write(vals)
[исходный код]
использоватьпоставлятьизценить更новыйтекущий Записывать集серединаиз所иметь Записывать
параметр:
vals (dict) –нуждаться更новыйиз Поле及верноотвечатьизценить,например:{'foo': 1, 'bar': "Qux"}
,Волянастраивать foo
ценитьдля 1
, bar
для"Qux"
,Если бы это было законно,в противном случае Волякурок错误。нуждаться特别Уведомлениеизда,Тем больше Поле нужно обновлять,Чем медленнее скорость обновления (автор обнаружил на практике,Но я не проверял, связано ли это с типом и Поле,Особенно отношения Поле,связь Полеиз更новый可能会вызовверноотвечать Модельизwrite
метод,Если этот метод переопределен,Это также может привести к увеличению затрат времени,в общем,соблюдать принцип,Обновляйте только те элементы, которые необходимо обновить)
ValidationError – Если пользователь пытается ввести неверную цену, которая находится за пределами выбора UserError–если Волясуществоватьобъект层次结构серединасоздаватьцикл,если в результате операции в иерархии объектов будет создан цикл (например, установка объекта в качестве собственного родителя)
дляцифровой Поле(odoo.fields.Integer
,odoo.fields.Float
) ,ценить должно соответствовать типу
для odoo.fields.Boolean
, ценитьдолжендляbool
тип
дляodoo.fields.Selection
, ценитьдолженсоответствоватьвыбиратьценить(в целомдляstr
,иметьчасдляint
)
дляodoo.fields.Many2one
,ценитьMustдля Идентификатор записи в базе данных
Другие не-отношения,использоватьхарактернитьценить
Опасность
По историческим причинам и соображениям совместимости,odoo.fields.Date
иodoo.fields.Datetime
Полеиспользоватьхарактернитьделатьдляценить(писатьичитать),而Нетдаdate
илиdatetime
。ЭтидатахарактернитьтолькодляUTCФормат,ив соответствии сodoo.tools.misc.DEFAULT_SERVER_DATE_FORMAT
иodoo.tools.miisc.DEFAULT_SERVER _DATETIME_FORMAT
进行Формат化
odoo.fields.One2many
иodoo.fields.Many2many
использовать特殊из“Заказ”Формат Приходитьдействоватьхранится в Полесередина/и Полеассоциацияиз Записывать集。
Этот формат представляет собой последовательно выполняемый список троек, где каждая тройка представляет собой команду, выполняемую в наборе записей. Не все команды применимы во всех ситуациях. Возможные команды:
(0, 0, values)
从поставлятьизvalues
словарьсоздаватьновый рекорд,形нравиться (0, 0, {'author': user_root.id, 'body': 'one'})
。
(1, id, values)
использоватьvalues
ценить обновление idценитьдля в указанном словареid
Существующие записи для ценить. Нет могу быть там 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, 0, 0)
,Затем, чтобыids
серединаизкаждыйidиспользовать Заказ(4, id, 0)
。Практические выводы,Против One2manyПоле,еслиids
верноотвечать ЗаписыватьизMany2one
Поле没хранилищетекущий Модельпервичный ключIDценитьчас,Не могущийиспользовать Должен Заказ。
действительныйиспользоватьчас,Эти Заказ可к Группа合использовать,следующее,ДаватьfieldName
настраиватьценитьчас,会先обозначение Заказ5
,существоватьосуществлять Заказ 0
Model.write({'fieldName': [(5, 0, 0), (0, 0, dict_value)]})
Model.flush(fnames=None, records=None)
[исходный код]
处理所иметьобращаться定извычислить(существовать所иметь Модельначальство),Обработайте все ожидающие вычисления (на всех моделях) и сбросьте все ожидающие обновления в базу данных.
fnames
), Ограничить область обработки заданными записями.
Model.browse([ids])
→ records[исходный код]
существоватьтекущийсредасередина查询ids
параметробозначениеиз Записыватьивозвращаться Записыватьрезультат集,Если для предложения параметр,илипараметрдля[]
,Затем появляется пустой набор результатов
self.browse([7, 18, 12])
res.partner(7, 18, 12)
Model.search(args[, offset=0][, limit=None][, order=None][, count=False])
[исходный код]
на основеargs
поиск домена搜索Записывать
[]
представлятьсоответствовать所иметь Записывать。
offset (int) – Результаты, которые следует игнорировать записей (по умолчанию: 0)
limit (int) – максимумвозвращаться Количество записей (по умолчаниювозвращаться所иметь) order (str) – Сортировать строку
count (bool) – еслидляTrue
,тольковычислитьивозвращатьсясоответствоватьиз Количество записей (по умолчанию: False)limit
Статьи совпадают Критерии запись определения
Model.search_count(args)
→ int[исходный код]
возвращатьсятекущий Модельсерединасоответствоватьпоставлятьизпоиск доменаargs
из Количество записей.
Model.name_search(name='', args=None, operator='ilike', limit=100)
→ records[исходный код]
搜索Сравнивать显示имяи Давать定name
соответствовать(соответствовать Способдля Давать定operator
),исоответствоватьпоиск доменаargs
из Записывать
Например,этот用于на основесвязь Полеиз部точкаценитьпоставлять建议。иметьчасодеяло视дляname_get()
из反函数,Но нет никакой гарантии, что это так.
此метод等效于использоватьна основеdisplay_name
изпоиск доменавызовsearch()
,Затемверно搜索результатосуществлять“name_get()”关于搜索результат
name
из域действовать,например 'like'
или '='
limit (int) – Необязательныйпараметр,возвращатьсямаксимум Количество записейlist
(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
Полеточка Группаиз Записыватьсписок。
[]
поверхность示соответствовать所иметь
fields (list) – объектначальствообозначениеизсписок视图середина存существоватьиз Полесписок。каждый元素Или“field”(Полеимя,использоватьпо умолчаниюполимеризация),Или“field:agg”(использоватьполимеризация函数“agg”полимеризация Поле),Либо это“name:agg(field)”(использовать“agg'полимеризация Полеи Воля Чтокогда做“name”возвращаться)。可能изполимеризация函数дляPostgreSQLпоставлятьиз函数(https://www.postgresql.org/docs/current/static/functions-aggregate.html),и «count_dict»,具иметь预期含义。
groupby (list) – Записыватьточка Группа依据източка Группа依据描述список。groupby描述Или Поле(Затем Воляв соответствии с Должен Полеточка Группа),Либо строка «поле:groupby_function». в настоящий момент,唯один支持из函数даday
、week
、month
、quarter
илиyear
,это们只Применимый于date/datetime
Поле
offset (int) – Количество, которое нужно пропустить записи, необязательный параметр.
limit (int) – нуждатьсявозвращатьсяизмаксимум Количество записи, необязательный параметр
orderby (str) – Сортировать строку(текущийтолько支持Many2one
Поле)。Необязательныйпараметр。
lazy (bool) – еслидляTrue
,норезультат只в соответствии с第одинgroupbyточка Группа,Что余groupbyвставить__context
键середина。еслидляFalse
,Тогда вся группировка выполняется за один вызов.groupby
параметрсерединаобозначение Полеточка Группа后из Полеизценить
__domain
: обозначение Критерии Список кортежей по заявкам
__context
: 拥иметьпохожийgroupby
параметризсловарь
[{‘field_name_1’: value, …]
Model.copy_data()
拷贝текущий Модель Записыватьиз数据,появился словарь,Ключ словарядля модели Название поля,keyценитьдляверноотвечатьиз Полеценить。Уведомление:возвращатьсясловарьkeyНет ВключатьOdoo系统自动生成из Модельповерхность Поле:create_uid
,create_date
,write_date
,write_uid
,id
Model.fields_get([fields][, attributes])
[исходный код]
станет определение каждого поляка
придет ценить - словарь, содержащий словари (индексированные по имени Поле). В том числе наследство Поле. Строка ВоляConvert, атрибуты helpиselection (если есть)
[]
ноповерхность示所иметь
attributes – Каждому Поле требуется список описаний атрибутов для появления. если未поставлятьилидля[]
ноповерхность示所иметь
Model.fields_view_get([view_id | view_type='form'])
[исходный код]
Получите подробный состав запрошенного представления, например Поле, модель, архитектуру представления.
view_id
дляNone
из话(‘form’, ‘tree’, …)
toolbar (bool) – настраиватьдляTrue
к Включатьначальство下文действовать
submenu – Устарело
dict
домен — это список критериев,каждыйстандартный Вседа(field_name,operator,value)
из三кортеж(один“список”или“кортеж”),в:
field_name
(str
)
Поле имени текущего модуля илипроходитьMany2one
,использоватьточка符Числоизсвязь遍历,Например 'street'
или'partner_id.country'
operator
(str
)
用于Сравниватьfield_name
иvalue
изоператор。иметь效оператордля:
=
равный
!=
Нетравный >
больше, чем
>=
больше, чемравный
<
меньше, чем
<=
меньше, чемравный
=?
未настраиватьилиравный(еслиvalue
дляNone
илиFalse
новозвращатьсяTrue
,в противном случаеи=
один样)
=like
Воляfield_name
такой жеvalue
модельсоответствовать。модельсерединаиз下划线_
соответствовать任何один个характер;стоточка Число%
соответствовать任何ноль个или Несколькохарактеризхарактернить
like
Воляfield_name
такой же%value%
модельсоответствовать。похожий=like
,但дасоответствовать前использовать%
Упаковкаvalue
not like
не соответствует %value%
модель
ilike
С учетом регистраlike
not ilike
С учетом регистра not like
=ilike
С учетом регистра =like
in
равныйvalue
серединаиз任意项,value
отвечать Должендля项список
not in
Нетравныйvalue
серединаиз任意项
child_of
даvalue
Записыватьизchild(Потомки)(value
может бытьодин项илиодин项список)。учитывать Модельиз Семантика(то есть следуя_parent_name
имяизсвязь Поле)。
parent_of
даvalue
Записыватьизparent(предок)(value
может бытьодин项илиодин项список)。учитывать Модельиз Семантика(то есть следуя_parent_name
имяизсвязь Поле)
value
Тип переменной, должен быть такой сравнение женаминга Поле (через operator
)
Можно использовать префиксную форму оператора логики, объединяющую условия предметной области:
'&'
логика AND, По умолчанию используется действие, которое сочетается с условиями Воли. Арити 2 (Используйте следующие 2 стандарта или комбинации)
'|'
логика OR arity 2
'!'
логика *NOT * 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)
Model.unlink()
[исходный код]
Удалить записи из текущего набора записей
причина
AccessError –
Если у пользователя нет разрешения на отсоединение запрошенного объекта
Если пользователь пытается обойти правила доступа, выполните отсоединение объекта запроса.
UserError – Если запись является атрибутом по умолчанию для других записей
Model.ids
возвращатьсяиself
верноотвечатьизнастоящий实ЗаписыватьID
odoo.models.env
возвращаться Давать定Записывать集изсреда。типEnvironment
Model.exists()
→ records[исходный код]
появляется сам по себе в подмножестве записей и Воля удаляет записи, отмеченные для записей в кеше.
if record.exists():
...
в соответствии с约定,Воляновый рекордделатьдля现иметь Записыватьвозвращаться
Model.ensure_one()
[исходный код]
Убедитесь, что текущий набор записей содержит только одну запись.
причинаodoo.exceptions.ValueError – len(self) != 1
Model.name_get()
→ [id, name, ...][исходный код]
возвращатьсяself
середина Записыватьизтекстповерхность示形式。По умолчанию,дляdisplay_name
Полеизценить。
(id, text_repr)
Список пар ценить
Model.get_metadata()
[исходный код]
появятся метаданные о данной записи
module.name
Набор записей является неизменяемым,Но Можно использовать различные коллекции, комбинируя такие же коллекции моделей.,Так появился новый рекорд
record in set
возвращаться record
(Должен быть набор записей, содержащий только один элемент) Есть set
середина。 record not in set
Как раз наоборотset1 <= set2
andset1 < set2
возвращатьсяset1
лидаset2
из子集set1 >= set2
and set1 > set2
возвращатьсяset1
лидаset2
из超集set1 | set2
станет объединением двух наборов рекордов. Набор записей, содержащий все записи, которые присутствуют в обоих исходных наборах записей.set1 & set2
Получится пересечение двух наборов рекордов. В одном содержится только такой То же самое является набором записей, когда в двух исходных наборах записей есть записи.set1 - set2
возвращатьсяодин Включатьтолько Появиться вset1
серединаиз Записыватьиз Записывать集Набор записей является итерируемым,поэтомув целомизPythonИнструменты, доступные для конвертации(map()
,sorted()
,ifilter()
,…),Затем Эти函数возвращатьсяlist
илиiterator
,удалитьвернорезультатвызовметодилииспользоватьсобиратьдействоватьиз能力。
поэтому,Набор записей обеспечивает следующее начало срабатывания (если это возможно):
Model.filtered(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)
[исходный код]
Model.mapped(func)
[исходный код]
верноself
серединаиз所иметь Записыватьприложениеfunc
,и Волярезультатделатьдлясписокили Записывать集возвращаться(еслиfunc
возвращаться Записывать集)。последнийвозвращатьсяиз Записывать集из顺序да任意из。
func
дляFalse
новозвращатьсяself
делать用于所иметьself
середина Записыватьизfunc
извозвращатьсярезультат
# 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
records.mapped('partner_id')
# returns the union of all partner banks, with duplicates removed
records.mapped('partner_id.bank_ids')
аннотация
Начиная с V13, Поддержка Дуодуо Гуаньси к полям, работает как сопоставленный вызов:
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')
Model.sorted(key=None, reverse=False)
[исходный код]
возвращатьсяв соответствии сkey
排序из Записывать集 self
None
) – одинпараметриз函数,для Один ключ сравнения на запись,или Полеимя,илиNone
,еслидляNone
,Записыватьв соответствии с照по умолчанию Модельиз顺序排序
reverse (bool) – еслидляTrue
, получится результат сортировки в обратном порядке
# sort records by name
records.sorted(key=lambda r: r.name)
Odoo предлагает три различных типа жеиз机制,к模块化Способ Расширять Модель:
когдатакой жечасиспользовать_inherit
и _name
свойствочас,Odooиспользовать现иметь Модель(проходить_inherit
поставлять)делатьдляbaseсоздаватьновый Модель。новый Модель从Чтоbaseсерединаполучать所иметь Поле、Метод и метаинформация (по умолчанию ценить и т.д.).
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 = ['res.partner', 'md.status.mixin']
когдаиспользовать_inherit
但省немного_name
час,Новая модель Воля заменяет существующую модель.,实质начальство就дасуществоватьоригинальный Модельначальство Расширять。этотдля Воляновый Полеилиметод添加到现иметь Модель(существовать Что他模块серединасоздавать)или Настроитьили重новый Конфигурацияэто们(Например更改Чтопо умолчанию排序顺序)非常иметь用:
class Extension0(models.Model):
_name = 'extension.0'
_description = 'Extension zero'
name = fields.Char(default="A")
def func():
print('test a')
class Extension1(models.Model):
_inherit = 'extension.0'
description = fields.Char(default="Extended")
def func(): # Функция переопределения
print('test b')
record = env['extension.0'].create({})
record.read()[0]
возвращаться:
{'name': "A", 'description': "Extended"}
аннотация
Также будут появляться различные автоматически генерируемые поля, если они не отключены.
env['extension.0'].func({})
возвращаться:
test b
Уведомление:
Если такой же наследует абстрактный модуль и неабстрактный модуль,и把_name
Конфигурациядлянеабстрактный модуль,Поле абстрактного модуля также будет добавлено в таблицу, соответствующую неабстрактному модулю.
Третий механизм наследования обеспечивает большую гибкость (может быть изменен во время выполнения).,Но менее мощный:использовать_inherits
Модель,Волятекущий Модельсередина未找到из任何Полеиз查找委托Давать“children”Модель。委托проходить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})
предупреждать
использовать委托继承час,Метод не наследуется,Только Поле
предупреждать
_inherits
илимногоилименее осознанный,если可киз话避免用это(_inherits
is more or less implemented, avoid it if you can)_inherits
基本начальство没иметь实现,我们Нетверно最终行длядавать какие-либо гарантии。(chained _inherits
is essentially not implemented, we cannot guarantee anything on the final behavior)Полеопределениедля Модель类из类свойство。если Расширять Понятно Модель,还可кпроходитьсуществовать子类начальство重новыйопределение具иметь Взаимнотакой жеимяитипиз Поле Приходить Расширять Полеопределение。существовать В этом случае,Атрибуты Поле взяты из родительского класса,и переопределяется свойствами, заданными в подклассах.
Например,下面извторой类толькосуществовать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")
odoo14\custom\estate\models\estate_property_tag.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from odoo import models, fields
class EstatePropertyTag(models.Model):
_name = 'estate.property.tag'
_description = 'estate property tag'
_order = 'name'
name = fields.Char(string='tag', required=True)
color = fields.Integer(string='Color')
odoo14\custom\estate\models\estate_property_offer.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from odoo import models, fields
class EstatePropertyOffer(models.Model):
_name = 'estate.property.offer'
_description = 'estate property offer'
property_id = fields.Many2one('estate.property', required=True)
price = fields.Integer()
odoo14\custom\estate\models\estate_property_type.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from odoo import models, fields
class EstatePropertyType(models.Model):
_name = 'estate.property.type'
_description = 'estate property type'
name = fields.Char(string='name', required=True)
odoo14\custom\estate\models\estate_property.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from odoo import models, fields
class EstateProperty(models.Model):
_name = 'estate.property'
_description = 'estate property table'
_order = 'id desc'
name = fields.Char(required=True)
property_type_id = fields.Many2one("estate.property.type", string="PropertyType")
tag_ids = fields.Many2many("estate.property.tag")
offer_ids = fields.One2many("estate.property.offer", "property_id", string="PropertyOffer")
>>> self.env['estate.property.type']
estate.property.type()
# Создать одну запись
>>> self.env['estate.property.type'].create({'name':'house'})
estate.property.type(1,)
# Запрос записей по идентификатору
>>> self.env['estate.property.type'].browse([1])
estate.property.type(1,)
# Если список идентификаторов не указан и параметр не указан, появляется пустой набор записей.
>>> self.env['estate.property.type'].browse()
estate.property.type()
>>> self.env['estate.property.type'].browse([])
estate.property.type()
# копировать Записывать
>>> self.env['estate.property.type'].browse([1]).copy({'name':'garden'})
estate.property.type(2,)
# Для набора записей, который получает только одну запись, вы можете передать records.fieldName Способ цитирования соответствует Поле (читай Полеценить или присваивает ценить Поле)
>>> self.env['estate.property.type'].browse([2]).name
'garden'
# 更новый рекорд
>>> self.env['estate.property.type'].browse([1]).name
'house'
>>> self.env['estate.property.type'].browse([1]).write({'name':'garden'})
True
>>> self.env['estate.property.type'].browse([1]).name
'garden'
# Для набора записей, который получает только одну запись, вы можете передать records.fieldName Способ цитирования соответствует Поле (читай Полеценить или присваивает ценить Поле)
>>> self.env['estate.property.type'].browse([1]).name = 'house'
>>> self.env['estate.property.type'].browse([1]).name
'house'
# Вы не можете изменить его напрямую, попытавшись указать идентификатор в функции записи следующим образом. рекорд # Никакие записи не будут изменены и никакие записи не будут добавлены.
>>> self.env['estate.property.type'].write({'id':1, 'name':'apartment'})
True
>>> self.env['estate.property.type'].browse([1]).name
'house'
# по поиску набор записей запроса API
>>> self.env['estate.property.type'].search([])
estate.property.type(1, 2)
# Создание записей в пакетном режиме
# Создать тестовые данные
>>> self.env['estate.property.tag'].create([{'name': 'tag1', 'color': 1}, {'name': 'tag1', 'color': 2}, {'name': 'tag1', 'color': 3}])
estate.property.tag(1, 2, 3)
# Уведомление: Many2one введите ценить Поле, должен быть установлен идентификатор первичного ключа соответствующей записи для.
>>> self.env['estate.property'].create({'name': 'house in beijing', 'property_type_id': 1, 'tag_ids':[(0,0, {'name': 'tag1', 'color': 3})]})
estate.property(1,)
>>> self.env['estate.property'].search([])
estate.property(1,)
# Отношения запроса Полеценить
>>> self.env['estate.property'].browse([1]).property_type_id # Many2one
estate.property.type(1,)
>>> self.env['estate.property'].browse([1]).tag_ids # Many2many
estate.property.tag(4,)
# Обновить отношения Many2many Полеценить
>>> self.env['estate.property'].browse([1]).tag_ids.write({'name': 'tag4', 'color': 4})
True
>>> self.env['estate.property'].browse([1]).tag_ids.color
4
>>> self.env['estate.property.tag'].search([])
estate.property.tag(1, 2, 3, 4)
# Отношения запроса Полеценить
>>> self.env['estate.property'].browse([1]).offer_ids # One2many
estate.property.offer()
## Обновить отношения One2many Полеценить
# дляRelationship Поле Создать связанную запись
# (0, 0, values)
# Создать новый из предоставленного словаря `values`. рекорд。
>>> self.env['estate.property'].browse([1]).offer_ids = [(0, 0, {'property_id':1})]
>>> self.env['estate.property'].browse([1]).offer_ids
estate.property.offer(1,)
>>> self.env['estate.property'].browse([1]).offer_ids.property_id
estate.property(1,)
# Обновить атрибут отношения Поле по записи объекта ценить
# (1, id, values)
# использовать values ценить обновление idценитьдля в указанном словаре id Существующие записи для ценить. Нет могу быть там Используется в create().
>>> self.env['estate.property'].browse([1]).offer_ids = [(1, 1, {'price': 30000})]
>>> self.env['estate.property'].browse([1]).offer_ids.price
30000
# Удалить связанные записи Поле отношений
# (3, id, 0)
# Удалить запись с идентификатором дid из набора записей, но не удалить ее из базы данных, подразумевается, что для только разъединяет. Нет могу быть там Используется в create().
>>> self.env['estate.property'].browse([1]).offer_ids = [(3,1,0)]
>>> self.env['estate.property'].browse([1]).offer_ids
estate.property.offer()
# Воля已存существовать Записыватьтакой же Ассоциация «Поле отношений»
# (4, id, 0)
# Добавьте существующую запись с idдляid в набор записей.
>>> self.env['estate.property.offer'].browse([1])
estate.property.offer(1,)
>>> self.env['estate.property'].browse([1]).offer_ids = [(4,1,0)]
>>> self.env['estate.property'].browse([1]).offer_ids
estate.property.offer(1,)
# для Поле отношений Создание нескольких связанных записей одновременно
>>> self.env['estate.property'].browse([1]).offer_ids = [(0, 0, {'property_id':1, 'price': 100000}),(0, 0, {'property_id':1, 'price': 200000}), (0, 0, {'property_id':1, 'price': 200000}), (0, 0, {'property_id':1, 'price': 300000})]
>>> self.env['estate.property'].browse([1]).offer_ids
estate.property.offer(1, 2, 3, 4, 5)
# Заменить записи, связанные с отношением Поле
# (6, 0, ids)
# Заменить все существующие записи на основе списка идентификаторов, Эквивалентно использованию команды (5, 0, 0), затем используйте команду (4, id, 0)。
>>> self.env['estate.property'].browse([1]).offer_ids = [(3,1,0),(3,2,0)]
>>> self.env['estate.property'].browse([1]).offer_ids
estate.property.offer(3, 4, 5)
>>> self.env['estate.property'].browse([1]).offer_ids = [(6, 0, [1,2])] # Сообщить об ошибке, Потому что дляID 1,2 Соответствующая запись, чья Many2oneПолеценитьдляnull
# отношение дляMany2many Поле создает несколько связанных записей
>>> self.env['estate.property'].create({'name': 'house in shanghai'})
estate.property(2,)
>>> self.env['estate.property'].browse([2])
estate.property(2,)
>>> self.env['estate.property'].browse([2]).tag_ids
estate.property.tag()
>>> self.env['estate.property'].browse([2]).tag_ids = [(0, 0, {'name': 'tag5', 'color': 5}), (0, 0, {'name': 'tag6', 'color': 6}), (0, 0, {'name': 'tag7', 'color': 7})]
>>> self.env['estate.property'].browse([2]).tag_ids
estate.property.tag(5, 6, 7)
# Удалить записи, связанные со связью Поле
# (2, id, 0)
# Удалить запись с идентификатором id из набора записей, а затем удалить ее (из базы данных), могу быть тамcreate()серединаиспользовать
>>> self.env['estate.property'].browse([2]).tag_ids = [(2, 5, 0)]
2023-01-29 08:48:25,491 15984 INFO odoo odoo.models.unlink: User #1 deleted estate.property.tag records with IDs: [5]
>>> print( self.env['estate.property.tag'].browse([5]).exists())
estate.property.tag()
>>> if self.env['estate.property.tag'].browse([5]).exists():
... print('exists record with id equal 5')
...
>>>
# Создать тестовые данные
>>> self.env['estate.property.tag'].create({'name': 'tag8', 'color': 8})
estate.property.tag(8,)
>>> self.env['estate.property.tag'].create({'name': 'tag9', 'color': 9})
estate.property.tag(9,)
>>> self.env['estate.property'].browse([2])
estate.property(2,)
# Заменить записи, связанные с отношением Поле
# (6, 0, ids)
# Заменить все существующие записи на основе списка идентификаторов, Эквивалентно использованию команды (5, 0, 0), затем используйте команду (4, id, 0)。
>>> self.env['estate.property'].browse([2]).tag_ids
estate.property.tag(6, 7)
>>> self.env['estate.property'].browse([2]).tag_ids = [(6, 0 , [8, 9])]
>>> self.env['estate.property'].browse([2]).tag_ids
estate.property.tag(8, 9)
>>>
# Получить список записей Полеценить (связанные атрибуты записи ценить) через сопоставленные
>>> self.env['estate.property'].browse([2]).tag_ids.mapped('name')
['tag8', 'tag9']
>>> self.env['estate.property'].browse([2]).mapped('tag_ids')
estate.property.tag(8, 9)
>>> self.env['estate.property'].browse([2]).mapped('tag_ids').mapped('id'))
[8, 9]
# search api приложение
# поиск домена
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)])
estate.property.tag(6, 7, 8, 9)
# компенсировать
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)], offset=1)
estate.property.tag(7, 8, 9)
# Предел становится максимальным Количеством в рекордном наборе записей
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)], offset=1, limit=2)
estate.property.tag(7, 8)
# станет сортировка записей в наборе записей
# порядок убывания
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)], offset=1, limit=2, order = 'id desc')
estate.property.tag(8, 7)
# По возрастанию
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)], offset=1, limit=2, order = 'id')
estate.property.tag(7, 8)
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)], offset=1, limit=2, order = 'id asc')
estate.property.tag(7, 8)
# тольковозвращаться Количество записей
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)], count=True)
4
# Используйте search_count API достигает эквивалентных эффектов
>>> self.env['estate.property.tag'].search_count(args=[('id', '>', 5)])
4
# поиск сочетание условий домена
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5),('color', '<', 8)])
estate.property.tag(6, 7)
# получать Записать (установить) информацию
# ids
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)]).ids
[6, 7, 8, 9]
# env
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)]).env
<odoo.api.Environment object at 0x0000020E31C80080>
# name_get api использовать
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)]).name_get()
[(6, 'tag6'), (7, 'tag7'), (8, 'tag8'), (9, 'tag9')]
# get_metadata api использовать
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)]).get_metadata()
[{'id': 6, 'create_uid': (1, 'OdooBot'), 'create_date': datetime.datetime(2023, 1, 29, 8, 41, 10, 551001), 'write_uid': (1, 'OdooBot'), 'write_date': datetime.datetime(2023, 1, 29, 8,41, 10, 551001), 'xmlid': False, 'noupdate': False}, {'id': 7, 'create_uid': (1, 'OdooBot'), 'create_date': datetime.datetime(2023, 1, 29, 8, 41, 10, 551001), 'write_uid': (1, 'OdooBot'), 'write_date': datetime.datetime(2023, 1, 29, 8, 41, 10, 551001), 'xmlid': False, 'noupdate': False}, {'id': 8, 'create_uid': (1, 'OdooBot'), 'create_date': datetime.datetime(2023,1, 29, 8, 41, 10, 551001), 'write_uid': (1, 'OdooBot'), 'write_date': datetime.datetime(2023, 1, 29, 8, 41, 10, 551001), 'xmlid': False, 'noupdate': False}, {'id': 9, 'create_uid': (1, 'OdooBot'), 'create_date': datetime.datetime(2023, 1, 29, 8, 41, 10, 551001), 'write_uid': (1, 'OdooBot'), 'write_date': datetime.datetime(2023, 1, 29, 8, 41, 10, 551001), 'xmlid': False, 'noupdate': False}]
# использовать read_group Реализуйте групповое чтение.
>>> self.env['estate.property.tag'].create({'name': 'tag10', 'color': 9})
estate.property.tag(10,)
>>> self.env['estate.property.tag'].read_group([], fields=['color'], groupby=['color'])
[{'color_count': 1, 'color': 6, '__domain': [('color', '=', 6)]}, {'color_count': 1, 'color': 7, '__domain': [('color', '=', 7)]}, {'color_count': 1, 'color': 8, '__domain': [('color', '=', 8)]}, {'color_count': 2, 'color': 9, '__domain': [('color', '=', 9)]}]
# Получить определение поля
>>> self.env['estate.property.tag'].fields_get(['name'])
{'name': {'type': 'char', 'change_default': False, 'company_dependent': False, 'depends': (), 'manual': False, 'readonly': False, 'required': True, 'searchable': True, 'sortable': True
, 'store': True, 'string': 'tag', 'translate': False, 'trim': True}}
# откат
>>> self.env.cr.rollback()
>>> self.env['estate.property.tag'].search(args=[('id', '>', 5)], offset=1, limit=2, order = 'id')
estate.property.tag()
# осуществлять sql
self.env.cr.execute('TRUNCATE TABLE estate_property_tag_test CASCADE;')
self.env.cr.commit()
# Сброс автоматически увеличивающегося идентификатора первичного ключа для1 (идентификатор первичного ключа каждой таблицы существует с именем для tableName_id_seq (в рейтинге)
self.env.cr.execute('ALTER SEQUENCE estate_property_tag_test_id_seq RESTART WITH 1;')
self.env.cr.commit()
>>> self.env['estate.property.tag'].create([{'name': 'tag1', 'color': 1}, {'name': 'tag2', 'color': 2}, {'name': 'tag3', 'color': 3}])
estate.property.tag(1, 2, 3)
# Пакетное обновлениеновый рекорд Полеценить #Если в наборе записей несколько записей, его невозможно передать. records.fieldName = Цельценить Внедрение пакетных обновлений
>>> self.env['estate.property.tag'].browse([1,3]).write({'color':1})
True
>>> self.env['estate.property.tag'].browse([1,3]).mapped('color')
[1, 1]
# Изменение контекста набора записей запроса
>>> self.env['estate.property.tag'].browse([]).env.context
{'lang': 'en_US', 'tz': 'Europe/Brussels'}
>>> self.env['estate.property.tag'].with_context(is_sync=False).browse([]).env.context
{'lang': 'en_US', 'tz': 'Europe/Brussels', 'is_sync': False}
# with_contextиsudo共存часизиспользовать Способ
>>> self.env['estate.property.tag'].with_context(is_sync=False).sudo().browse([]).env.context
{'lang': 'en_US', 'tz': 'Europe/Brussels', 'is_sync': False}
>>> self.env['estate.property.tag'].sudo().with_context(is_sync=False).browse([]).env.context
{'lang': 'en_US', 'tz': 'Europe/Brussels', 'is_sync': False}
# Изменить контекст записи при создании записи (подробнее новый запись(запись) также используется таким же образом)
# нравиться此,Вы можете переопределить метод createилиwrite соответствующей модели.,И получить целевой ключценить через self.env.context в методе,а потомосуществлять需求实现нуждаться采取из动делать,См. ниже
>>> self.env['estate.property.tag'].with_context(is_sync=False).create({'name': 'tag4', 'color': 4}).env.context
{'lang': 'en_US', 'tz': 'Europe/Brussels', 'is_sync': False}
# удалить запись
>>> self.env['estate.property.tag'].search([])
estate.property.tag(1, 2, 3, 4)
>>> self.env['estate.property.tag'].search([('id', '>', 2)]).unlink()
2023-01-29 09:55:47,796 15984 INFO odoo odoo.models.unlink: User #1 deleted estate.property.tag records with IDs: [3, 4]
True
# Пройти набор записей
>>> for record_set in self. self.env['estate.property.tag.test'].search([]):
... print(record_set)
...
estate.property.tag.test(1,)
estate.property.tag.test(2,)
Получить контекстный целевой ключ контекстаценить Пример
#!/usr/bin/env python
# -*- coding:utf-8 -*-
from odoo import models, fields,api
class EstatePropertyTag(models.Model):
_name = 'estate.property.tag'
_description = 'estate property tag'
_order = 'name'
name = fields.Char(string='tag', required=True)
color = fields.Integer(string='Color')
@api.model
def create(self, vals_list):
res = super(EstatePropertyTag, self).create(vals_list)
# Получить контекстный целевой ключценить
if not self.env.context.get('is_sync', True):
# do something you need
return res
https://www.odoo.com/documentation/14.0/zh_CN/developer/reference/addons/orm.html#