Утиліти оновлення¶
Утиліти оновлення - це бібліотека, що містить допоміжні функції для полегшення написання скриптів оновлення. Ця бібліотека, яка використовується Odoo для скриптів оновлення стандартних модулів, забезпечує надійність і допомагає пришвидшити процес оновлення:
Допоміжні функції допомагають забезпечити узгодженість даних у базі даних.
Він обробляє непрямі посилання на оновлені записи.
Дозволяє викликати функції та уникнути написання коду, заощаджуючи час та зменшуючи ризики розробки.
Помічники дозволяють зосередитися на тому, що важливо для оновлення, і не думати про деталі.
Встановлення¶
Клонуйте репозиторій Репозиторій оновлення утиліт локально та запустіть odoo з каталогом src на початку параметра --upgrade-path.
$ ./odoo-bin --upgrade-path=/path/to/upgrade-util/src,/path/to/other/upgrade/script/directory [...]
На платформах, де ви не керуєте Odoo самостійно, ви можете встановити цю бібліотеку через pip:
$ python3 -m pip install git+https://github.com/odoo/upgrade-util@master
На Odoo.sh рекомендується додати його до requirements.txt користувацького репозиторію. Для цього додайте наступний рядок усередині файлу:
odoo_upgrade @ git+https://github.com/odoo/upgrade-util@master
Використання утиліт оновлення¶
Після встановлення для скриптів оновлення доступні такі пакети:
odoo.upgrade.util: сам помічник.odoo.upgrade.testing: базові класи TestCase.
Щоб використовувати його в скриптах оновлення, просто імпортуйте його:
from odoo.upgrade import util
def migrate(cr, version):
# Rest of the script
Тепер допоміжні функції доступні для виклику через util.
Функції утиліт¶
Утиліти оновлення - це бібліотека, що містить допоміжні функції для полегшення написання скриптів оновлення. Ця бібліотека, яка використовується Odoo для скриптів оновлення стандартних модулів, забезпечує надійність і допомагає пришвидшити процес оновлення.
Примітка
Параметр cr у корисних функціях завжди посилається на курсор бази даних. Передайте отриманий параметр як параметр у migrate(). Не всім функціям потрібен цей параметр.
Модулі¶
Функції утиліти для операцій на рівні модуля.
У більшості випадків операції з модулями (перейменування, об’єднання, видалення тощо) слід виконувати в скрипті base. Причина полягає в тому, що після оновлення модуля base вся інформація щодо модулів повинна бути вже встановлена в базі даних, щоб процес оновлення працював коректно. Опція командного рядка --pre-upgrade-scripts (доступна в Odoo 16) дозволяє запускати скрипти оновлення перед завантаженням base. Це рекомендований спосіб виконання операцій з модулями після значного оновлення.
- modules_installed(cr, *modules)[source]¶
Повертає, чи встановлено всі задані модулі.
Примітка
У контексті оновлень модуль вважається встановленим, якщо він позначений для оновлення або встановлення; навіть якщо вони ще не повністю встановлені.
- module_installed(cr, module)[source]¶
Повертає інформацію про те, чи встановлено модуль.
Див.
modules_installed().
- uninstall_module(cr, module)[source]¶
Деінсталювати та видалити всі записи, що належать модулю.
- Параметри
module (str) – назва модуля для видалення
- uninstall_theme(cr, theme, base_theme=None)[source]¶
Деінсталюйте модуль теми та видаліть його з вебсайтів.
- Параметри
Попередження
Цю функцію можна використовувати лише в
post-скриптах модуляwebsite, оскільки вона спирається на ORM.Див.
remove_theme()таuninstall_module().
- remove_module(cr, module)[source]¶
Повністю видалити модуль.
Ця операція еквівалентна деінсталяції та видаленню всіх посилань на модуль - жодних слідів від нього в базі даних не залишається.
- Параметри
module (str) – назва модуля, який потрібно видалити
Попередження
Оскільки ця функція видаляє всі дані, пов’язані з модулем, переконайтеся, що ви перепризначили записи перед викликом цієї функції.
- remove_theme(cr, theme, base_theme=None)[source]¶
Деінсталювати модуль теми.
Попередження
Цю функцію можна використовувати лише у скриптах
post-.Див.
remove_module()таuninstall_theme().
- merge_module(cr, old, into, update_dependers=True)[source]¶
Об’єднати модуль з іншим.
Ця функція переміщує всі посилання та записи з вихідного модуля до цільового модуля.
Попередження
Ця функція не видаляє жодних записів, але видаляє xml_ids з вихідного модуля з конфліктуючим ім’ям у цільовому модулі.
- force_install_module(cr, module, if_installed=None, reason='it has been explicitly asked for')[source]¶
Змусити ORM встановити модуль.
- force_upgrade_of_fresh_module(cr, module, init=True)[source]¶
Примусово запустити виконання скриптів оновлення для модуля, що встановлюється.
Стандартна версія Odoo не запускає скрипти оновлення під час інсталяції модуля. Це логічно, оскільки, з технічної точки зору, модуль не оновлюється. Проте трапляються випадки, коли (новий) модуль повинен виконати певні операції для правильної інсталяції, наприклад, отримати дані з іншого модуля. Це часто трапляється, коли модуль функціонально розділений на кілька модулів.
- Параметри
Перебування в режимі ініціалізації має побічний ефект неврахування прапорців noupdate ні в XML-файлі, ні в
ir_model_data.
- move_model(cr, model, from_module, to_module, move_data=False, keep=())[source]¶
Переміщення моделі з одного модуля до іншого.
- Параметри
model (str) – назва моделі для переміщення
from_module (str) – назва модуля, де модель спочатку визначена
to_module (str) – назва цільового модуля, куди потрібно перемістити модель
move_data (bool) – чи також оновлювати
ir_model_dataдля записів моделіkeep (list(str)) – список XML-ідентифікаторів, які потрібно зберегти, а не переміщувати
Цю функцію можна викликати для переміщення змін моделі до іншого модуля. Оскільки вона не може розрізнити вихідну модель від успадкованої, вона викликає виняток, якщо цільовий модуль не встановлено.
Моделі¶
Допоміжні функції для модифікації моделей.
Операції з моделлю найкраще виконувати в pre- скриптах задіяних модулів.
- remove_model(cr, model, drop_table=True, ignore_m2m=())[source]¶
Видалити модель та її посилання з бази даних.
Деякі обов’язкові непрямі посилання на модель замінюються на невідому модель - порожню модель, яка слугує заповнювачем для зниклих моделей.
- delete_model(cr, model, drop_table=True, ignore_m2m=())[source]¶
Видалити модель та її посилання з бази даних.
Деякі обов’язкові непрямі посилання на модель замінюються на невідому модель - порожню модель, яка слугує заповнювачем для зниклих моделей.
- rename_model(cr, old, new, rename_table=True, ignored_m2ms='ALL_BEFORE_18_1')[source]¶
Перейменування моделі.
Оновлює всі посилання на назву моделі в базі даних.
Якщо запитується перейменування таблиці, починаючи з saaas~18.1+, таблиці m2m також оновлюються, якщо їх не ігнорувати. У старіших версіях таблиці m2m пропускаються, якщо не передається порожній список.
- Параметри
old (str) – назва поточної моделі
new (str) – нова назва моделі
rename_table (bool) – чи також перейменувати таблицю моделі
ignored_m2ms – таблиці m2m, які потрібно пропустити. За замовчуванням використовується значення
"ALL_BEFORE_18_1", що пропускає всі в Odoo 18 або старішій версії, жодні в saa~18.1+. Для всіх версій, якщо значення не є значенням за замовчуванням, пропускаються лише вказані таблиці m2m.
- merge_model(cr, source, target, drop_table=True, fields_mapping=None, ignore_m2m=())[source]¶
Об’єднати модель з іншою.
Ця функція переміщує всі посилання з моделі
sourceв модельtargetі видаляє модельsourceта її посилання. За замовчуванням, з моделі-джерела в модель-ціль переміщуються лише поля з однаковими іменами в обох моделях, але за бажанням можна надати відповідність полів з різними іменами.Попередження
Ця функція не переміщує записи з моделі
sourceдо моделіtarget.- Параметри
source (str) – назва моделі, яку потрібно об’єднати
target (str) – назва цільової моделі для об’єднання
drop_table (bool) – чи слід видаляти таблицю вихідної моделі
fields_mapping (dict or None) – зіставлення назв полів з вихідної моделі в цільову, при використанні
Noneпереміщуються лише поля з однаковими назвамиignore_m2m (list(str) or str) – список таблиць m2m, які ігноруються для видалення з вихідної моделі.
- remove_inherit_from_model(cr, model, inherit, keep=(), skip_inherit=(), with_inherit_parents=True)[source]¶
Видаліть
inheritзmodel.Ця функція видаляє всі поля, успадковані через
inheritзmodelта всіх його похідних моделей. Всі поля з успадкованих моделей, включаючи ті, що належать до батьківських моделей, також видаляються, якщо не встановлено режимwith_inherit_parents. У такому випадку видаляються тільки поля зinherit, за винятком полів у батьківських моделях. Поля, перелічені вkeep, ніколи не видаляються. Якщо деякі нащадки зmodelперелічені вskip_inherit, вони збережуть поля зinherit.- Параметри
model (str) – назва моделі, з якої потрібно видалити успадкування
inherit (str) – назва успадкованої моделі (або міксину), яку потрібно видалити
keep (tuple(str)) – кортеж із іменами полів, які потрібно зберегти
skip_inherit (tuple(str)) – список моделей-нащадків
model, які не потрібно оброблятиwith_inherit_parents (boolean) – якщо не встановлено, видаляти поля лише з
inherit, зберігаючи всі поля від батьківських елементів
Поля¶
Функції утиліти для зміни полів моделі.
Виїздні операції найкраще виконувати в скрипті pre- відповідних модулів. У деяких випадках попередню операцію можна виконати в pre, а завершити в post. Типовим прикладом є видалення поля в pre із збереженням його стовпця, який згодом використовується в post, коли стовпець остаточно видаляється.
- remove_field(cr, model, fieldname, cascade=False, drop_column=True, skip_inherit=(), keep_as_attachments=False)[source]¶
Видалити поле та посилання на нього з бази даних.
Ця функція також видаляє поле з моделей, що успадковуються, якщо винятки не вказані в
skip_inherit. Коли поле зберігається, ми можемо вибрати, щоб стовпець не видалявся.- Параметри
model (str) – назва моделі поля, яке потрібно видалити
fieldname (str) – назва поля, яке потрібно видалити
cascade (bool) – чи видаляються стовпці поля в режимі
CASCADEdrop_column (bool) – чи стовпець поля видалено
skip_inherit (list(str) or str) – список моделей-успадкувань, щоб пропустити видалення поля, використовуйте
"*", щоб пропустити всіkeep_as_attachments (bool) – для бінарних полів, чи слід зберігати дані як вкладення
- move_field_to_module(cr, model, fieldname, old_module, new_module, skip_inherit=())[source]¶
Переміщення поля з одного модуля до іншого.
Ця функція оновлює всі посилання на певне поле, перемикаючись з вихідного модуля на цільовий. Це запобігає видаленню даних після повного завантаження реєстру. Поля в успадковуваних моделях також переміщуються, якщо їх не пропускати.
- Параметри
model (str) – назва власника моделі поля для переміщення
fieldname (str) – назва поля для переміщення
old_module (str) – назва вихідного модуля, з якого переміщується поле
new_module (str) – назва цільового модуля, в який переміщується поле
skip_inherit (list(str) or str) – список моделей-успадкувань, для яких поле не потрібно переміщувати, використовуйте
"*", щоб пропустити всі
- rename_field(cr, model, old, new, update_references=True, domain_adapter=None, skip_inherit=())[source]¶
Перейменувати поле та його посилання зі
oldнаnewу заданійmodel.Поле оновлюється у всіх успадковуваних моделях, окрім моделей, зазначених у
skip_inherit.Ця функція також оновлює посилання, прямі чи непрямі, включаючи фільтри, дії сервера, пов’язані поля, електронні листи, інформаційні панелі, домени тощо. Див.
update_field_usage()Для оновлення доменів можна використовувати спеціальну функцію адаптера. Адаптер за замовчуванням просто замінює
oldнаnewу кожному листку домену. Зверніться доadapt_domains()для отримання інформації про адаптери доменів.- Параметри
model (str) – назва моделі поля, яке потрібно перейменувати
old (str) – поточна назва поля, яке потрібно перейменувати
new (str) – нова назва поля для перейменування
update_references (bool) – чи оновлювати всі посилання
domain_adapter (function) – адаптер для використання з доменами, див.
adapt_domains()skip_inherit (list(str) or str) – моделі, які потрібно пропустити під час перейменування поля в успадковуваних моделях, використовуйте
"*", щоб пропустити всі
- invert_boolean_field(cr, model, old, new, skip_inherit=())[source]¶
Перейменувати логічне поле та інвертувати його значення.
- convert_m2o_field_to_m2m(cr, model, field, new_name=None, m2m_table=None, col1=None, col2=None)[source]¶
Перетворити поле типу Many2one на поле типу Many2many.
Це створює таблицю зв’язків та заповнює її.
- Параметри
model (str) – назва моделі поля для перетворення
field (str) – поточна назва поля для перетворення
new_name (str) – нова назва поля для конвертації. Якщо не вказано, це буде
fieldз завершальною літерою «s».m2m_table (str) – назва таблиці зв’язків. Автоматично генерується, якщо не вказано.
col1 (str) – назва стовпця, що посилається на
model.col2 (str) – назва стовпця, що посилається на ціль
field.
- m2o2m2m(cr, model, field, new_name=None, m2m_table=None, col1=None, col2=None)[source]¶
Перетворити поле типу Many2one на поле типу Many2many.
Це створює таблицю зв’язків та заповнює її.
- Параметри
model (str) – назва моделі поля для перетворення
field (str) – поточна назва поля для перетворення
new_name (str) – нова назва поля для конвертації. Якщо не вказано, це буде
fieldз завершальною літерою «s».m2m_table (str) – назва таблиці зв’язків. Автоматично генерується, якщо не вказано.
col1 (str) – назва стовпця, що посилається на
model.col2 (str) – назва стовпця, що посилається на ціль
field.
- change_field_selection_values(cr, model, field, mapping, skip_inherit=())[source]¶
Замінити посилання на значення поля вибору.
Ця функція замінює всі посилання на значення вибору відповідно до зіставлення. Домени також оновлюються.
- Параметри
model (str) – назва моделі поля вибору, яке потрібно оновити
field (str) – назва поля вибору, яке потрібно оновити
mapping (dict) – значення вибору для оновлення, ключові значення замінюються відповідними значеннями у відповідності
skip_inherit (list(str) or str) – список успадкованих моделей, які потрібно пропустити під час оновлення значень вибору, використовуйте
"*", щоб пропустити всі
- update_field_usage(cr, model, old, new, domain_adapter=None, skip_inherit=())[source]¶
Замініть усі посилання на поле
oldнаnewу різних місцях.- Пошук у:
ir_filters
ir_exports_line
ir_act_server
mail_alias
ir_ui_view_custom (інф. панель)
домени (за допомогою
domain_adapter)пов’язані поля
Ця функція може бути використана для заміни використання одного поля іншим. Домени оновлюються за допомогою
domain_adapter. За замовчуванням адаптер домену просто замінюєoldнаnewу листі домену. Дивітьсяadapt_domains()для отримання додаткової інформації про адаптери домену.- Параметри
model (str) – назва моделі поля
old (str) – вихідна назва поля, яке потрібно замінити
new (str) – цільова назва поля, яку потрібно встановити
domain_adapter (function) – адаптер для використання з доменами, див.
adapt_domains()skip_inherit (list(str) or str) – моделі, які потрібно пропустити під час перейменування поля в успадковуваних моделях, використовуйте
"*", щоб пропустити всі
Запис¶
Функції утиліти для операцій на рівні записів.
- remove_view(cr, xml_id=None, view_id=None, silent=False, key=None)[source]¶
Видалити представлення та всіх його нащадків.
Ця функція рекурсивно видаляє задане представлення та успадковані від нього представлення, якщо вони є частиною модуля. Вона завершить роботу, щойно в ієрархії з’явиться користувацьке представлення. Вона також видаляє представлення COW для кількох веб-сайтів.
- Параметри
xml_id (str) – необов’язково, xml_id представлення, яке потрібно видалити
view_id (int) – необов’язково, ID представлення, яке потрібно видалити
silent (bool) – чи показувати в журналах вимкнені користувацькі представлення
key (str or None) – ключ, що використовується для виявлення представлень COW з кількох веб-сайтів. Якщо значення
None, тоді значенняxml_id, якщо воно надано, інакше значення xml_id, що посилається на перегляд з IDview_id, якщо такий є.
Попередження
Потрібно встановити або
xml_id, абоview_id. Вказівка обох призведе до помилки.
- edit_view(cr, xmlid=None, view_id=None, skip_if_not_noupdate=True, active='auto')[source]¶
Менеджер контексту для редагування arch представлення.
Ця функція повертає контекстний менеджер, який може повернути розібрану структуру представлення як etree Element. Будь-які зміни, зроблені в поверненому об’єкті, будуть записані назад у базу даних після виходу з контекстного менеджера, оновлюючи також перекладені версії структури. Оскільки функція може не повертати результат, використовуйте
skippable_cm(), щоб уникнути помилок.with util.skippable_cm(), util.edit_view(cr, "xml.id") as arch: arch.attrib["string"] = "My Form"
Щоб вибрати цільове представлення для редагування, використовуйте або
xmlid, абоview_id, а не обидва одночасно.Коли вид ідентифікується за допомогою
view_id, arch завжди передається, якщо представлення існує, незважаючи на будь-який прапорnoupdate, який може бути з ним пов’язаний. Коли встановленоxmlid, якщо прапорnoupdateпредставлення має значенняFalse, arch не буде передана, якщоskip_if_not_noupdateне встановлено наFalse. Якщоnoupdateмає значенняTrue, представлення буде передано для редагування.Якщо аргумент
activeмає значенняTrueабоFalse, прапорецьactiveпредставлення буде встановлено відповідно.Примітка
Якщо
activeмає значення «автоматично» (значення за замовчуванням), представлення буде активоване, якщо вибрано черезxmlid, і залишиться незмінним, якщо вибрано черезview_id.- Параметри
xmlid (str) – необов’язково, xml_id редагування представлення
view_id (int) – необов’язково, ID представлення даних для редагування
skip_if_not_noupdate (bool) – чи слід примусово редагувати представлення, запитувані через параметр
xmlid, навіть якщо вони позначені якnoupdate=True, ігнорується, якщо встановленоview_idactive (bool or None or "auto") – значення активного прапорця, яке потрібно встановити. Не змінюється, якщо
None.
- Повертає
менеджер контексту, який видає проаналізовану арку, після виходу менеджер контексту записує зміни назад.
- remove_record(cr, name)[source]¶
Видалити запис та посилання на нього, що відповідають заданому xml_id.
- Параметри
name (str) – запис xml_id у форматі
module.name
- is_changed(cr, xmlid, interval='1 minute')[source]¶
Повертає інформацію про те, чи було змінено запис.
Ця функція перевіряє, чи запис було змінено до поточного часу початку оновлення. Див.
upgrade-util/src/base/0.0.0/pre-00-upgrade-start.pyЦя утиліта повертатиме хибнопозитивний результат для xmlid записів, які відповідають таким умовам:
Були оновлені в оновленні, що передувало поточному
Не оновлювалися в поточному оновленні
Якщо
xmlidне існує в базі даних, ця функція повертаєNone.
- if_unchanged(cr, xmlid, callback, interval='1 minute', **kwargs)[source]¶
Виконати
callback, якщо запис не змінився.Ця функція запустить
callback, коли зазначений запис не змінився.xmlidта будь-які додаткові параметри, крімinterval, будуть передані доcallback. У разі зміни запису він буде позначений якnoupdate=True. Див. такожis_changed()таforce_noupdate().Ця функція корисна для виконання дії тільки, коли запис не було оновлено. Типовим прикладом є примусове оновлення з XML, навіть якщо запис мав значення
noupdate=True.util.if_unchanged(cr, "mymodule.myrecord", util.update_record_from_xml)
- Параметри
xmlid (str) – xml_id запису для перевірки
callback (function) – зворотний виклик для виконання у випадку, якщо запис не було змінено, всі додаткові параметри цієї функції передаються до зворотного виклику
interval (str) – інтервал після
create_date, у який запис вважається _changed_, див.is_changed()
- rename_xmlid(cr, old, new, noupdate=None, on_collision='fail')[source]¶
Перейменувати external identifier (
xml_id) запису.Перейменування неможливе, якщо цільова назва вже існує в базі даних. У таких випадках є два варіанти керування поведінкою цієї функції:
fail: викликати виняток та запобігти перейменуваннюmerge: перейменувати зовнішній ідентифікатор, видалити старий та замінити посилання. Див.replace_record_references_batch()
Примітка
Ця функція не видаляє записи, вона лише оновлює xml_ids.
- Параметри
old (str) – поточний xml_id запису у форматі
module.namenew (str) – новий xml_id запису у форматі
module.namenoupdate (bool or None) – значення, яке потрібно встановити для прапорця
noupdatexml_id, ігнорується, якщоNoneon_collision (str) – як діяти далі, якщо xml_id вже існує, варіанти:
mergeабоfail(за замовчуванням)
- Повертає
ID запису, на який посилається новий xml_id,
None, якщо запис не існує- Тип повернення
- ensure_xmlid_match_record(cr, xmlid, model, values)[source]¶
Переконайтеся, що xml_id посилається на запис із певними значеннями.
Ця функція гарантує, що запис, на який вказує xml_id, відповідає значенням для полів, зазначених у параметрі
values. Коли xmlid існує, але вказує на запис, який не відповідає значенням, xmlid оновлюється, щоб вказувати на запис, який відповідає значенням, якщо такий знайдено. Якщо xmlid не існує, він створюється зі знайденим записом. Якщо відповідний запис не знайдено, нічого не робиться. У всіх випадках повертається запис, на який посилається, після можливого оновлення xml_id.- Параметри
- Повертає
ідентифікатор запису, що відповідає значенню,
None, якщо запис не знайдено- Тип повернення
Порада
Ця функція корисна під час міграції записів з бази даних у користувацький модуль, щоб створити xml_ids перед оновленням модуля та уникнути дублювання.
- update_record_from_xml(cr, xmlid, reset_write_metadata=True, force_create=AUTO, from_module=None, reset_translations=(), ensure_references=False, fields=None)[source]¶
Оновити запис на основі його визначення у файлі Файли даних.
Ця функція ігнорує прапорець
noupdateу записі. Вона шукає відповідне визначення у всіх XML-файлах з маніфесту модуля в xmlid або в параметріfrom_module, якщо він встановлений. Знайшовши його, вона змушує ORM оновити запис, як зазначено у специфікаціях у файлі даних.За бажанням, ця функція може скинути переклади деяких полів.
- Параметри
xmlid (str) – запис xml_id у форматі
module.namereset_write_metadata (bool) – чи оновлювати
write_dateзаписуforce_create (bool) – чи створюється запис, якщо його не існує. За замовчуванням значення
True, якщоfieldsне дорівнює None.from_module (str) – назва модуля, з якого оновлюється запис, необхідна лише тоді, коли специфікації знаходяться в іншому модулі, ніж той, що в xml_id
reset_translations (set(str)) – назви полів, переклади яких скидаються
ensure_references (bool) – чи слід також оновлювати записи, на які посилаються через атрибути XML
ref.fields (set(str) or None) – необов’язковий список полів для включення до XML-оголошення. Якщо встановлено, всі інші поля будуть ігноруватися. Якщо встановлено, запис не буде створено, якщо його немає.
Попередження
Ця функція використовує ORM, тому її можна використовувати лише після того, як всі моделі, на які посилаються в специфікаціях даних запису, вже завантажені. На практиці це означає, що цю функцію слід використовувати в скриптах
post-абоend-.Примітка
Стандартна поведінка ORM полягає у створенні запису, якщо він не існує, включаючи його xml_id. Це також станеться в цій функції, якщо тільки для
force_createне встановлено значенняFalse.
- delete_unused(cr, *xmlids, **kwargs)[source]¶
Видаліть невикористані записи.
Ця функція видалятиме записи, на які вказує
xmlids, лише якщо на них немає посилання з жодної таблиці. Для ієрархічних записів (наприклад, категорій продуктів) вона перевіряє, чи немає посилання на дочірні записи, позначені як каскадне видалення. У такому разі запис та його дочірні елементи видаляються.Примітка
Записи, які не можна видалити, встановлюються як
noupdate=True.- Параметри
xmlids (list(str)) – список xml_ids для перевірки на видалення
deactivate (bool) – чи деактивувати записи, які неможливо видалити, оскільки на них є посилання, за замовчуванням
Falsekeep_xmlids (bool) – чи зберігати xml_ids записів, які не можна видалити. За замовчуванням
Trueдля версій до 18.0,Falseпочинаючи зsaas~18.1.
- Повертає
список ідентифікаторів видалених записів, якщо такі є
- Тип повернення
- replace_record_references_batch(cr, id_mapping, model_src, model_dst=None, replace_xmlid=True, ignores=(), parent_field='parent_id')[source]¶
Замініть усі посилання на записи.
Ця функція замінює всі посилання, прямі чи непрямі, на записи
model_srcвідповідними записами у відображенні. Якщо цільова модель відображення відрізняється від вихідної, тоді необхідно встановити параметрmodel_dst.- Параметри
id_mapping (dict(int, int)) – зіставлення ідентифікаторів для заміни, значення ключа замінюється зіставленим значенням
model_src (str) – назва вихідної моделі записів, які потрібно замінити
model_dst (str) – назва цільової моделі записів, які потрібно замінити; якщо
None, ціль вважається такою ж, як і джерелоreplace_xmlid (bool) – чи замінювати посилання в xml_ids, що вказують на вихідні записи
ignores (list(str)) – список назв**таблиць**, які потрібно пропустити під час оновлення значень, на які посилаються
- Paream str parent_field
Коли цільова та вихідна моделі однакові, і таблиця моделі має стовпець
parent_path, це поле буде використано для її оновлення.
- replace_in_all_jsonb_values(cr, table, column, old, new, extra_filter=None)[source]¶
Замінити значення у колонках JSONB.
Ця функція замінює
oldнаnewу значеннях JSONB. Вона корисна для заміни значень у всіх перекладах перекладених полів.- Параметри
table (str) – назва таблиці, де потрібно замінити значення
column (str) – назва колонки, де потрібно замінити значення
old (str) – початкове значення для заміни може бути простим терміном (str) або регулярним виразом Postgres, обгорнутим
PGRegexpnew (str) – нове значення, яке потрібно встановити, може бути простим терміном або виразом з використанням нотації
<number>для позначення захоплених груп, якщоoldє регулярним виразомextra_filter (str) – додатковий сумісний з
WHEREпункт для фільтрації значень для оновлення, необхідно використовувати алыасtдля таблиці, він також може включати{parallel_filter}для паралельного виконання запиту, див.explode_execute()
ORM¶
Допоміжні функції для виконання операцій через ORM.
Функції цього модуля дозволяють безпечно використовувати ORM під час оновлень. Вони покращують або виправляють ORM таким чином, щоб він міг ефективно обробляти великі обсяги даних. У деяких випадках надаються повністю альтернативні функції до власних функцій ORM. Функції цього модуля працюють з ORM всіх підтримуваних версій.
- env(cr)[source]¶
Створіть нове середовище.
Попередження
Ця функція не очищує кеш, що зберігається на курсорі для суперкористувача з порожнім середовищем. Виклик
invalidate_cacheможе знадобитися щоразу, коли дані змінюються безпосередньо в базі даних.- Повертає
нове середовище
- Тип повернення
- recompute_fields(cr, model, fields, ids=None, logger=<Logger odoo.upgrade.util.orm (WARNING)>, chunk_size=256, strategy='auto', query=None)[source]¶
Переобчислити значення полів.
Ця функція перераховує поля моделі, обмежені набором записів - або всіма. Перерахунок не виконується одночасно для всіх записів. Він розділений на партії (блоки). Це дозволяє уникнути проблем з продуктивністю і, в гіршому випадку, збоїв через
MemoryError. Після обробки кожного блоку дані відправляються назад до бази даних відповідно до однієї з наступних стратегій:flush: використовувати метод
flushORMcommit:
commitкурсор - також скинутиauto: вибрати найкращий варіант між двома вищезазначеними, враховуючи кількість записів для обчислення та наявність відстежуваних полів.
Стратегія commit менш схильна до виникнення помилки
MemoryErrorдля величезного обсягу даних.- Параметри
model (str) – назва моделі для переобчислення
ids (list(int) or None) – список ідентифікаторів записів для переобчислення, коли
Noneпереобчислює всі записи, якщо також не встановленоquery(див. нижче)logger (
logging.Logger) – логер, який використовується для звітування про прогресchunk_size (int) – кількість записів на фрагмент – використовується для розділення обробки
strategy (str) – стратегія, що використовується для обробки перерахунку
query (str) – query to get the IDs of records to recompute, it is an error to set both
idsandquery. Note that the processing will always happen in ascending order. If that is unwanted, you must useidsinstead.
- class iter_browse(model, *args, **kw)[source]¶
Ітерація понад наборів записів.
Об’єкт
callable, що повертається цим класом, можна використовувати як ітератор, який завантажує записи фрагментами (уrecordset). Після вичерпання кожного фрагмента його дані надсилаються назад до бази даних (очищаються або фіксуються) і завантажується новий фрагмент.Цей клас дозволяє виконувати код, подібний до:
for record in env['my.model'].browse(ids): record.field1 = val env['my.model'].browse(ids)._compute_field2() env['my.model'].create(values)
продуктивним способом, водночас уникаючи
MemoryError, навіть колиidsабоvaluesмають мільйони записів. Альтернативою використання цього класу буде:Example
MyModel = util.env(cr)['my.model'] for record in util.iter_browse(MyModel, ids): record.field1 = val util.iter_browse(MyModel, ids)._compute_field2() util.iter_browse(MyModel, ids).create(values)
- Параметри
model (
odoo.model.Model) – модель для ітераціїids (list(int)) – список ідентифікаторів записів для ітерації
chunk_size (int) – кількість записів для завантаження в кожному фрагменті ітерації, за замовчуванням
200logger (
logging.Logger) – логер, який використовується для звітування про прогрес, за замовчуванням_loggerstrategy (str) – чи потрібно
flush, чиcommitдля кожного фрагмента, за замовчуваннямflush
- Повертає
об’єкт, що повертається цим класом, можна використовувати для ітерації або безпечного виклику будь-якого методу моделі на мільйонах записів.
Див. також
env()
- adapt_domains(cr, model, old, new, adapter=None, skip_inherit=(), force_adapt=False)[source]¶
Замініть
oldнаnewв доменах, використовуючиmodelта успадковуючи моделі.adapter- це функція зворотного виклику для адаптації листя. Функції адаптера повинні приймати три аргументи та повертати domain, який замінює оригінальне листя. Аргументи:leaf: лист домену, який єtupleвиду(left, op, right)in_or: логічне значення, колиTrueозначає, що лист є частиною домену АБО ("|"), інакше він є частиною домену І ("&").negated: логічне значення, колиTrueозначає, що листок заперечений ("!")
Example
def adapter(leaf, in_or, negated): left, op, right = leaf ok, ko = (1, 2) if not negated else (2, 1) if op == "=" return [(left, "=", ok)] elif op == "!=": return [(left, "=", ko)] return [leaf]
adapterвикликається лише на листках, які використовують полеoldmodelяк остання частинуleftчастини leaves, якщоforce_adaptне має значенняTrue. В останньому випадку адаптер викликається, якщо поле з’являється будь-де в шляху, що корисно лише для реляційних полів.У доменах, що повертаються адаптером, не потрібно замінювати поле
oldнаnewу лівій частині вхідного аркуша. Заміна все одно буде виконана для всього домену, що повертається адаптером. Звичайне призначенняadapter- змінити оператор та праву частину вхідного аркуша. Якщоadapterне встановлено, відбувається лише заміна.Example
Під час заміни
"field1"на"field2"відбувається наступне:("foo.bar.baz.field1", "=", 1)адаптується тільки, якщо запис, на який вказуєfoo.bar.baz, належить до запитуваноїмоделі.("foo.field1.baz", "=", 1)не адаптується навіть якщоfooвказує наmodel, окрім випадків, колиforce_adaptмає значенняTrue, оскількиfield1не є останньою частиноюleftу цьому листі.
Примітка
Ця функція замінить домени у всіх стандартних полях доменів. Включно з фільтрами, інформаційними панелями та стандартними полями, які, як відомо, представляють домен.
- Параметри
model (str) – назва моделі, для якої потрібно адаптувати домени
old (str) – назва поля, яке потрібно адаптувати
new (str) – назва поля, яке має замінити
oldadapter (function) – адаптер для відпусток
skip_inherit (list(str)) – список успадкованих назв моделей, які не потрібно адаптувати (пропустити)
force_adapt (bool) – якщо
True, запускатиadapterна всіх листках, що маютьnewу лівій частині листка (шляху), корисно під час видалення поля (у цьому випадкуnewігнорується).
SQL¶
Функції утилыти для взаємодії з PostgreSQL.
- class PGRegexp[source]¶
Обгортка для семантичного значення параметрів: цей рядок є регулярним виразом Postgres.
- class SQLStr[source]¶
Обгортка для семантичного значення параметрів: цей рядок є коректним фрагментом SQL.
Див.
format_query()
- parallel_execute(cr, queries, logger=<Logger odoo.upgrade.util.pg (WARNING)>)[source]¶
Виконуйте запити паралельно.
Example
util.parallel_execute(cr, [util.format_query(cr, "REINDEX TABLE {}", t) for t in tables])
Порада
Якщо ви хочете пришвидшити виконання одного запиту, дивіться
explode_execute().- Параметри
- Повертає
сума
cr.rowcountдля кожного виконання запиту- Тип повернення
Попередження
Через особливості функції
cr.rowcount, значення, яке повертає ця функція, може бути заниженим порівняно з реальним числом записів, на які впливає операція. Наприклад, якщо деякі записи видаляються/оновлюються в результаті використання оператораondelete, вони не враховуються.Як побічний ефект, курсор буде зафіксовано.
Примітка
Якщо виникне проблема паралельності, невдалі запити будуть повторені послідовно.
- format_query(cr, query, *args, **kwargs)[source]¶
Безпечно форматуйте запит.
Аргументи
strцієї функції вважаються ідентифікаторами SQL. Вони обертаються подвійними лапками перед розгортанням за допомогоюstr.format(). Також допускаються будь-які інші psycopg2.sql.Composable. Сюди входитьColumnList, див. такожget_columns()Example
>>> util.format_query(cr, "SELECT {0} FROM {table}", "id", table="res_users") SELECT "id" FROM "res_users"
- Параметри
query (str) – запит для форматування, можна використовувати дужки
{}, як уstr.format()
- explode_execute(cr, query, table, alias=None, bucket_size=10000, logger=<Logger odoo.upgrade.util.pg (WARNING)>)[source]¶
Виконайте запит паралельно.
Запит розділяється на групи ідентифікаторів, а потім обробляється паралельно працівниками. Якщо запит не містить спеціального значення
{parallel_filter}, воно додається до останнього оператораWHERE, а також може бути додане, якщо його не знайдено. Якщо запит вже містить фільтр, нічого не робиться. Фільтр завжди розширюється до стратегії розділення. Розділення здійснюється на групи, в яких для кожного окремого запиту оновлюється не більше ніжbucket_sizeідентифікаторів.Example
util.explode_execute( cr, ''' UPDATE res_users u SET active = False WHERE (u.login LIKE 'dummy' OR u.login = 'bob') AND {parallel_filter} ''', table="res_users" alias="u", )
- Параметри
query (str) – запит для виконання.
table (str) – назва головної таблиці запиту, що використовується для розділення обробки
alias (str) – аліас, який використовується для головної таблиці в запиті
bucket_size (int) – розмір корзин ідентифікаторів для розділення обробки
logger (
logging.Logger) – логер, який використовується для звітування про прогрес
- Повертає
сума
cr.rowcountдля кожного виконання запиту- Тип повернення
Попередження
Користувач, який здійснює виклик, повинен переконатися, що запити не оновлюють одні й ті ж записи в різних сегментах. Не рекомендується використовувати цю функцію для запитів
DELETEу таблицях із самопосиланнями через можливі наслідкиON DELETE. Для отримання додаткової інформації див.: func:~odoo.upgrade.util.pg.parallel_execute.
- create_column(cr, table, column, definition, **kwargs)[source]¶
Створити колонку.
Ця функція створить колонку тільки в тому випадку, якщо він не існує. Вона зареєструє помилку, якщо існуюча колонка має інший тип. Якщо встановлено
fk_table, вона забезпечить налаштування зовнішнього ключа, оновлюючи його за необхідності, з правильнимon_delete_action, якщо такий встановлено.- Параметри
table (str) – таблиця нової колонки
column (str) – назва нової колонки
definition (str) – тип колонки нової колонки
default (bool) – значення за замовчуванням, яке потрібно встановити для нової колонки
fk_table (bool) – якщо нова колонка, якщо зовнішній ключ, назва зовнішньої таблиці
on_delete_action (str) – Речення
ON DELETE, за замовчуваннямNO ACTION, дійсне лише якщо колонка є зовнішнім ключем.
- Повертає
чи було створено колонку
- Тип повернення
- alter_column_type(cr, table, column, type, using=None, where=None, logger=<Logger odoo.upgrade.util.pg (WARNING)>)[source]¶
Змінити тип колонки.
Зробіть це ефективно, використовуючи тимчасову колонку та паралельні запити UPDATE.
- Параметри
table (str) – назва відповідної колонки.
column (str) – назва колонки, тип якого потрібно змінити.
type (str) – новий тип колонки.
using (str) – SQL-вираз, що визначає, як конвертувати значення в новий тип. Заповнювач
{0}буде замінено назвою стовпця.where (str) – використовується для обмеження значень, перетворених за допомогою
using.logger (
logging.Logger) – логер, який використовується для звітування про прогрес.
- remove_constraint(cr, table, name, cascade=False, warn=True)[source]¶
Видалити обмеження таблиці.
Ця функція видаляє обмеження
nameзtable. Вона також видаляє записи зir_model_constraintта його xml_ids. Вона реєструє не знайдені обмеження.Примітка
Якщо обмеження
nameвідсутнє, ця функція спробує видалити{table}_{name}, останнє є ім’ям за замовчуванням, яке ORM використовує для обмежень, створених з_sql_constraints.- Параметри
- Повертає
чи було знято обмеження
- Тип повернення
- class ColumnList(list_=(), quoted=())[source]¶
Інкапсулюйте список елементів, що представляють назви стовпців.
Результуючий об’єкт можна відобразити як рядок з початковою/кінцевою комою або аліасом.
- Параметри
Example
>>> columns = ColumnList(["id", "field_Yx"], ["id", '"field_Yx"'])
>>> list(columns) ['id', '"field_Yx"']
>>> columns.using(alias="t").as_string(cr._cnx) '"t"."id", "t"."field_Yx"'
>>> columns.using(leading_comma=True).as_string(cr._cnx) ', "id", "field_Yx"'
>>> util.format_query(cr, "SELECT {} t.name FROM table t", columns.using(alias="t", trailing_comma=True)) 'SELECT "t"."id", "t"."field_Yx", t.name FROM table t'
>>> columns = ColumnList.from_unquoted(cr, ["foo", "BAR"])
>>> list(columns) ['"foo"', '"BAR"']
>>> list(columns.iter_unquoted()) ['foo', 'BAR']
Примітка
Цей клас краще використовувати через
get_columns()- classmethod from_unquoted(cr, list_)[source]¶
Створіть ColumnList зі списку назв колонок, які можуть потребувати лапок.
- get_columns(cr, table, ignore=('id',))[source]¶
Повернути список колонок у таблиці.
- Параметри
- Повертає
список назв колонок, присутніх у таблиці
- Тип повернення
- get_common_columns(cr, table1, table2, ignore=('id',))[source]¶
Повернути список колонок, присутніх в обох таблицях.
- Параметри
- Повертає
список назв колонок, присутніх в обох таблицях
- Тип повернення
- rename_table(cr, old_table, new_table, remove_constraints=True)[source]¶
Перейменувати таблицю.
Ця функція перейменовує таблицю
old_tableнаnew_table, а також її первинний ключ (та послідовність), індекси та зовнішні ключі.
- create_m2m(cr, m2m, fk1, fk2, col1=None, col2=None)[source]¶
Переконайтеся, що таблиця m2m існує або створена.
Ця функція створює таблицю, пов’язану з полем m2m. Якщо таблиця вже існує, для неї виконується
fixup_m2m(). Ім’я таблиці може бути згенеровано автоматично, застосовуючи ту саму логіку ORM. Для цього використовуйте значення «auto» для параметраm2m.- Параметри
m2m (str) – назва таблиці для створення, якщо
AUTO, вона генерується автоматичноfk1 (str) – перша назва таблиці зовнішнього ключа
fk2 (str) – назва другої таблиці зовнішнього ключа
col1 (str) – стовпець, що посилається на
fk1, за замовчуванням має значення"{fk1}_id"col2 (str) – стовпець, що посилається на
fk2, за замовчуванням має значення"{fk2}_id"
- Повертає
назва щойно створеної/виправленої таблиці
- Тип повернення
- bulk_update_table(cr, table, columns, mapping, key_col='id')[source]¶
Оновити таблицю на основі зіставлення.
Кожен запис
mappingвизначає нові значення для вказанихстовпцівдля рядка(ів), значенняkey_colяких відповідає ключу.Example
# single column update util.bulk_update_table(cr, "res_users", "active", {42: False, 27: True}) # multi-column update util.bulk_update_table( cr, "res_users", ["active", "password"], { "admin": [True, "1234"], "demo": [True, "5678"], }, key_col="login", )
- Параметри
table (str) – таблиця для оновлення.
columns (str | list(str)) – cпецифікація стовпців для оновлення. Це може бути назва одного стовпця або список назв стовпців.
mappingмає відповідати специфікації.mapping (dict) – значення, які потрібно встановити, і які мають відповідати специфікації в
columns, дотримуючись того самого порядкуkey_col (str) – стовпець, який використовується як ключ для отримання значень з
mappingпід час оновлення.
Попередження
Значення у мапінгу будуть приведені до типу цільового стовпця. Ця функція призначена для оновлення скалярних значень, щоб уникнути встановлення масивів або JSON-даних через мапінг.
Різне¶
Різні автономні функції.
- version_gte(version)[source]¶
Повертає, чи поточна версія Odoo більша або дорівнює
version.Ця функція корисна для умовного виконання в скрипті оновлення, який застосовується до кількох версій, наприклад, скрипти
0.0.0.
- version_between(a, b)[source]¶
Повертає, чи знаходиться поточна версія Odoo в діапазоні
[a,b].Див. також
version_gte()Примітка
Межі є інклюзивними.
- expand_braces(s)[source]¶
Розгорнути фігурні дужки у вхідних даних.
Example
>>> util.expand_braces("a_{this,that}_b") ['a_this_b', 'a_that_b']
- Параметри
s (str) – рядок, який потрібно розгорнути, повинен містити рівно одну пару фігурних дужок.
- Повертає
розширений вхід
- import_script(path, name=None)[source]¶
Імпортуйте скрипт оновлення.
Ця функція дозволяє імпортувати функції з інших скриптів оновлення в поточний.
Example
У
mymodule/15.0.1.0/pre-migrate.pydef my_util(cr): # do stuff
У
myothermodule/16.0.1.0/post-migrate.pyfrom odoo.upgrade import util script = util.import_script("mymodule/15.0.1.0/pre-migrate.py") def migrate(cr, version): script.my_util(cr) # reuse the function
Ця функція повертає
модульPython.>>> util.import_script("base/0.0.0/end-moved0.py", name="my-moved0") <module 'my-moved0' from '/home/odoo/src/upgrade-util/src/base/0.0.0/end-moved0.py'>
- Параметри
- Повертає
модуль, створений з імпортованого скрипта оновлення
- skippable_cm()[source]¶
Повернути менеджер контексту, щоб дозволити іншому менеджеру контексту не надавати дані.
Див.
edit_view()для прикладу використання.
- chunks(iterable, size, fmt=None)[source]¶
Розділити
iterableна фрагменти розміромsizeта обгорнути кожен фрагмент за допомогою функціїfmt.Ця функція корисна для розділення величезних вхідних даних на менші фрагменти, які можна обробляти незалежно.
Example
>>> list(chunks(range(10), 4, fmt=tuple)) [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9)] >>> ' '.join(chunks('abcdefghijklm', 3)) 'abc def ghi jkl m'
- Параметри
iterable (iterable) – ітерований об’єкт для розділення
size (int) – розмір фрагмента
fmt (function) – функція, яка застосовується до кожного фрагмента, коли передається
None,fmtстає"".join, якщоiterable– це рядок, інакшеiter
- Повертає
генератор, який перебирає результат
fmt, застосований до кожного фрагмента
Testing upgrade scripts¶
There are two main classes used testing during the upgrade.
UpgradeCasefor testing upgrade scripts,UpgradeCasefor testing invariants across versions.
Subclasses must implement:
For
UpgradeCase:preparemethod: prepare data before upgrade,checkmethod: check data was correctly upgraded.
For
IntegrityCase:invariantmethod: compute an invariant to check.
Put your test classes in a tests Python module (folder) in any of the folders
containing the upgrade scripts of your modules. The script containing your tests must
have a test_ prefix. The tests module must contain an __init__.py file to be
detected by Odoo.
Example directory structure:
myupgrades/
└── mymodule1/
├── 18.0.1.1.2/
│ └── pre-myupgrade.py
└── tests/
├── __init__.py
└── test_myupgrade.py
Примітка
The tests in the example above will be loaded only if mymodule1 is being
upgraded.
Running Upgrade Tests¶
After receiving an upgraded database with all standard Odoo modules already upgraded to their target version, you can test the upgrade of custom modules by following a three-step process:
Prepare the test data
$ ~/odoo/$version/odoo-bin -d DB --test-tags=$prepare_test_tag \ --upgrade-path=~/upgrade-util/src,~/myupgrades \ --addons=~/odoo/$version/addons,~/enterprise/$version,~/mymodules --stop
Upgrade the modules
$ ~/odoo/$version/odoo-bin -d DB -u mymodule1,mymodule2 \ --upgrade-path=~/upgrade-util/src,~/myupgrades \ --addons=~/odoo/$version/addons,~/enterprise/$version,~/mymodules --stop
Check the upgraded data
$ ~/odoo/$version/odoo-bin -d DB --test-tags=$check_test_tag \ --upgrade-path=~/upgrade-util/src,~/myupgrades \ --addons=~/odoo/$version/addons,~/enterprise/$version,~/mymodules --stop
The example above assumes that $version is the target version of your upgrade (e.g.
18.0), DB is the name of your database, and mymodule1,mymodule2 are the
modules you want to upgrade. The directory structure assumes that ~/odoo/$version and
~/enterprise/$version contain the Community and Enterprise source code for the target
Odoo version, respectively. ~/mymodules contains the code of your custom modules
(mymodule1, …), ~/myupgrades contains your custom upgrade scripts, and
~/upgrade-util contains the upgrade utils
repo.
The variables $prepare_test_tag and $check_test_tag must be set according to:
Variable |
|
|
|---|---|---|
|
|
|
|
|
|
Примітка
upgrade.test_prepare also runs IntegrityCase tests, so you can prepare data
for both UpgradeCase and IntegrityCase tests with only this tag.
Попередження
Do not run any prepare method of an UpgradeCase before sending your
database for a production upgrade to upgrade.odoo.com. Doing so may risk your upgrade being blocked and marked
as failed.
API documentation¶
- parametrize(argvalues)[source]¶
Parametrize a test function.
Decorator for upgrade test functions to parametrize and generate multiple tests from it.
Usage:
@parametrize([(1, 2), (2, 4), (-1, -2), (0, 0)]) def test_double(self, input, expected): self.assertEqual(input * 2, expected)
Works by injecting test functions in the containing class. Inspired by the parameterized package.
- change_version(version_str)[source]¶
Class decorator to specify the version on which a test is relevant.
Using
@change_version(version)indicates:test_preparewill only run if the current Odoo version is in the range[next_major_version-1, version).test_checkwill only run if the current Odoo version is in the range[version, next_major_version).
next_major_versionis the next major version afterversion, e.g. forsaas~17.2it is18.0.Примітка
Do not use this decorator if your upgrade is in the same major version. Otherwise, your tests will not run.
- class UpgradeCase(methodName='runTest')[source]¶
Test case to verify that the upgrade scripts correctly upgrade data.
Override:
prepareto set up data,checkto assert expectations after the upgrade.
The ORM can be used in these methods to perform the functional flow under test. The return value of
prepareis persisted and passed as an argument tocheck. It must be JSON-serializable.Примітка
Since
prepareinjects or modifies data, this type of test is intended only for development. Use it to test upgrade scripts while developing them. Do not run these tests for a production upgrade. To verify that upgrades preserved important invariants in production, useIntegrityCasetests instead.Example
from odoo.upgrade.testing import UpgradeCase, change_version class DeactivateBobUsers(UpgradeCase): def prepare(self): u = self.env["res.users"].create({"login": "bob", "name": "Bob"}) return u.id # will be passed to check def check(self, uid): # uid is the value returned by prepare self.env.cr.execute( "SELECT * FROM res_users WHERE id=%s AND NOT active", [uid] ) self.assertEqual(self.env.cr.rowcount, 1)
- class IntegrityCase(methodName='runTest')[source]¶
Test case for validating invariants across upgrades.
Override:
invariantto return a JSON-serializable value representing the invariant to check.
The
invariantmethod is called both before and after the upgrade, and the results are compared.Example
from odoo.upgrade.testing import IntegrityCase class NoNewUsers(IntegrityCase): def invariant(self): return self.env["res.users"].search_count([])