Утиліти оновлення

Утиліти оновлення - це бібліотека, що містить допоміжні функції для полегшення написання скриптів оновлення. Ця бібліотека, яка використовується 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]

Повертає, чи встановлено всі задані модулі.

Параметри

modules (list(str)) – назви модулів для перевірки

Тип повернення

bool

Примітка

У контексті оновлень модуль вважається встановленим, якщо він позначений для оновлення або встановлення; навіть якщо вони ще не повністю встановлені.

module_installed(cr, module)[source]

Повертає інформацію про те, чи встановлено модуль.

Параметри

module (str) – назва модуля для перевірки

Тип повернення

bool

Див. modules_installed().

uninstall_module(cr, module)[source]

Деінсталювати та видалити всі записи, що належать модулю.

Параметри

module (str) – назва модуля для видалення

uninstall_theme(cr, theme, base_theme=None)[source]

Деінсталюйте модуль теми та видаліть його з вебсайтів.

Параметри
  • theme (str) – назва модуля теми, який потрібно деінсталювати

  • base_theme (str or None) – якщо не None, спочатку вивантажити цю базову тему

Попередження

Цю функцію можна використовувати лише в 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().

rename_module(cr, old, new)[source]

Перейменувати модуль та всі посилання на нього.

Параметри
  • old (str) – поточна назва модуля для перейменування

  • new (str) – нова назва модуля для перейменування

merge_module(cr, old, into, update_dependers=True)[source]

Об’єднати модуль з іншим.

Ця функція переміщує всі посилання та записи з вихідного модуля до цільового модуля.

Попередження

Ця функція не видаляє жодних записів, але видаляє xml_ids з вихідного модуля з конфліктуючим ім’ям у цільовому модулі.

Параметри
  • old (str) – назва модуля, який потрібно об’єднати

  • into (str) – назва модуля, з яким потрібно об’єднати

  • update_dependers (bool) – чи оновлюються залежності модулів, що залежать від old

force_install_module(cr, module, if_installed=None, reason='it has been explicitly asked for')[source]

Змусити ORM встановити модуль.

Параметри
  • module (str) – назва модуля для встановлення

  • if_installed (list(str) or None) – примусово встановлювати лише тоді, коли ці модулі вже встановлені

повернути str

новий стан модуля

force_upgrade_of_fresh_module(cr, module, init=True)[source]

Примусово запустити виконання скриптів оновлення для модуля, що встановлюється.

Стандартна версія Odoo не запускає скрипти оновлення під час інсталяції модуля. Це логічно, оскільки, з технічної точки зору, модуль не оновлюється. Проте трапляються випадки, коли (новий) модуль повинен виконати певні операції для правильної інсталяції, наприклад, отримати дані з іншого модуля. Це часто трапляється, коли модуль функціонально розділений на кілька модулів.

Параметри
  • module (str) – назва модуля, для якого потрібно примусово виконати скрипти оновлення

  • init (bool) – чи встановити модуль у режим init

Перебування в режимі ініціалізації має побічний ефект неврахування прапорців 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]

Видалити модель та її посилання з бази даних.

Деякі обов’язкові непрямі посилання на модель замінюються на невідому модель - порожню модель, яка слугує заповнювачем для зниклих моделей.

Параметри
  • model (str) – назва моделі, яку потрібно видалити

  • drop_table (bool) – чи слід видаляти таблицю цієї моделі

  • ignore_m2m (list(str) or str) – список таблиць m2m, які потрібно ігнорувати - не видаляється, використовуйте "*", щоб ігнорувати (зберегти) всі таблиці m2m

delete_model(cr, model, drop_table=True, ignore_m2m=())[source]

Видалити модель та її посилання з бази даних.

Деякі обов’язкові непрямі посилання на модель замінюються на невідому модель - порожню модель, яка слугує заповнювачем для зниклих моделей.

Параметри
  • model (str) – назва моделі, яку потрібно видалити

  • drop_table (bool) – чи слід видаляти таблицю цієї моделі

  • ignore_m2m (list(str) or str) – список таблиць m2m, які потрібно ігнорувати - не видаляється, використовуйте "*", щоб ігнорувати (зберегти) всі таблиці m2m

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) – чи видаляються стовпці поля в режимі CASCADE

  • drop_column (bool) – чи стовпець поля видалено

  • skip_inherit (list(str) or str) – список моделей-успадкувань, щоб пропустити видалення поля, використовуйте "*", щоб пропустити всі

  • keep_as_attachments (bool) – для бінарних полів, чи слід зберігати дані як вкладення

make_field_non_stored(cr, model, field, selectable=False)[source]

Перетворити поле на non-stored.

Параметри
  • model (str) – назва моделі поля для перетворення

  • fieldname (str) – назва поля для конвертації

  • selectable (bool) – чи поле все ще можна вибрати, якщо True користувацькі ir.filters не оновлюються

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, що посилається на перегляд з ID view_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_id

  • active (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.

Параметри
  • xmlid (str) – xmlid запису для перевірки

  • interval (str) – Інтервал SQL, запис вважається зміненим, якщо write_date > create_date + interval

Тип повернення

bool or 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.name

  • new (str) – новий xml_id запису у форматі module.name

  • noupdate (bool or None) – значення, яке потрібно встановити для прапорця noupdate xml_id, ігнорується, якщо None

  • on_collision (str) – як діяти далі, якщо xml_id вже існує, варіанти: merge або fail (за замовчуванням)

Повертає

ID запису, на який посилається новий xml_id, None, якщо запис не існує

Тип повернення

int or None

ref(cr, xmlid)[source]

Повертає id, що відповідає заданому xml_id.

Параметри

xml_id (str) – запис xml_id у форматі module.name

Повертає

ID запису, на який посилаються, None, якщо не знайдено.

Тип повернення

int or None

force_noupdate(cr, xmlid, noupdate=True, warn=False)[source]

Оновити прапорець noupdate запису.

Параметри
  • xmlid (str) – запис xml_id у форматі module.name

  • noupdate (bool) – значення, яке потрібно встановити для прапорця noupdate

  • warn – чи виводити попередження в журнали, коли прапорець було змінено з True на False

ensure_xmlid_match_record(cr, xmlid, model, values)[source]

Переконайтеся, що xml_id посилається на запис із певними значеннями.

Ця функція гарантує, що запис, на який вказує xml_id, відповідає значенням для полів, зазначених у параметрі values. Коли xmlid існує, але вказує на запис, який не відповідає значенням, xmlid оновлюється, щоб вказувати на запис, який відповідає значенням, якщо такий знайдено. Якщо xmlid не існує, він створюється зі знайденим записом. Якщо відповідний запис не знайдено, нічого не робиться. У всіх випадках повертається запис, на який посилається, після можливого оновлення xml_id.

Параметри
  • xmlid (str) – запис xml_id у форматі module.name

  • model (str) – назва моделі запису

  • values (dict) – зіставлення назв полів зі значеннями, яким має відповідати запис .. example:: .. code-block:: python values = {«id»: 123} values = {«name»: «INV/2024/0001», «company_id»: 1}

Повертає

ідентифікатор запису, що відповідає значенню, None, якщо запис не знайдено

Тип повернення

int or 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.name

  • reset_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) – чи деактивувати записи, які неможливо видалити, оскільки на них є посилання, за замовчуванням False

  • keep_xmlids (bool) – чи зберігати xml_ids записів, які не можна видалити. За замовчуванням True для версій до 18.0, False починаючи з saas~18.1.

Повертає

список ідентифікаторів видалених записів, якщо такі є

Тип повернення

list(int)

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, обгорнутим PGRegexp

  • new (str) – нове значення, яке потрібно встановити, може бути простим терміном або виразом з використанням нотації <number> для позначення захоплених груп, якщо old є регулярним виразом

  • extra_filter (str) – додатковий сумісний з WHERE пункт для фільтрації значень для оновлення, необхідно використовувати алыас t для таблиці, він також може включати {parallel_filter} для паралельного виконання запиту, див. explode_execute()

ORM

Допоміжні функції для виконання операцій через ORM.

Функції цього модуля дозволяють безпечно використовувати ORM під час оновлень. Вони покращують або виправляють ORM таким чином, щоб він міг ефективно обробляти великі обсяги даних. У деяких випадках надаються повністю альтернативні функції до власних функцій ORM. Функції цього модуля працюють з ORM всіх підтримуваних версій.

env(cr)[source]

Створіть нове середовище.

Попередження

Ця функція не очищує кеш, що зберігається на курсорі для суперкористувача з порожнім середовищем. Виклик invalidate_cache може знадобитися щоразу, коли дані змінюються безпосередньо в базі даних.

Повертає

нове середовище

Тип повернення

Environment

recompute_fields(cr, model, fields, ids=None, logger=<Logger odoo.upgrade.util.orm (WARNING)>, chunk_size=256, strategy='auto', query=None)[source]

Переобчислити значення полів.

Ця функція перераховує поля моделі, обмежені набором записів - або всіма. Перерахунок не виконується одночасно для всіх записів. Він розділений на партії (блоки). Це дозволяє уникнути проблем з продуктивністю і, в гіршому випадку, збоїв через MemoryError. Після обробки кожного блоку дані відправляються назад до бази даних відповідно до однієї з наступних стратегій:

  • flush: використовувати метод flush ORM

  • commit: commit курсор - також скинути

  • auto: вибрати найкращий варіант між двома вищезазначеними, враховуючи кількість записів для обчислення та наявність відстежуваних полів.

Стратегія commit менш схильна до виникнення помилки MemoryError для величезного обсягу даних.

Параметри
  • model (str) – назва моделі для переобчислення

  • fields (list(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 ids and query. Note that the processing will always happen in ascending order. If that is unwanted, you must use ids instead.

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) – кількість записів для завантаження в кожному фрагменті ітерації, за замовчуванням 200

  • logger (logging.Logger) – логер, який використовується для звітування про прогрес, за замовчуванням _logger

  • strategy (str) – чи потрібно flush, чи commit для кожного фрагмента, за замовчуванням flush

Повертає

об’єкт, що повертається цим класом, можна використовувати для ітерації або безпечного виклику будь-якого методу моделі на мільйонах записів.

Див. також env()

create(values, **kw)[source]

Створюйте записи.

Альтернатива методу create за замовчуванням в ORM, яку безпечно використовувати для створення мільйонів записів.

Параметри
  • values (list(dict)) – список значень записів, які потрібно створити

  • multi (bool) – чи використовувати багатофункціональну версію create, за замовчуванням True з Odoo 12 і вище

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 викликається лише на листках, які використовують поле old model як остання частину 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) – назва поля, яке має замінити old

  • adapter (function) – адаптер для відпусток

  • skip_inherit (list(str)) – список успадкованих назв моделей, які не потрібно адаптувати (пропустити)

  • force_adapt (bool) – якщо True, запускати adapter на всіх листках, що мають new у лівій частині листка (шляху), корисно під час видалення поля (у цьому випадку new ігнорується).

SQL

Функції утилыти для взаємодії з PostgreSQL.

class PGRegexp[source]

Обгортка для семантичного значення параметрів: цей рядок є регулярним виразом Postgres.

Див. replace_in_all_jsonb_values()

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().

Параметри
  • queries (list(str)) – список запитів для одночасного виконання

  • logger (Logger) – логер, який використовується для звітування про прогрес

Повертає

сума cr.rowcount для кожного виконання запиту

Тип повернення

int

Попередження

  • Через особливості функції 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 для кожного виконання запиту

Тип повернення

int

Попередження

Користувач, який здійснює виклик, повинен переконатися, що запити не оновлюють одні й ті ж записи в різних сегментах. Не рекомендується використовувати цю функцію для запитів DELETE у таблицях із самопосиланнями через можливі наслідки ON DELETE. Для отримання додаткової інформації див.: func:~odoo.upgrade.util.pg.parallel_execute.

column_exists(cr, table, column)[source]

Повертає інформацію про існування колонки.

Параметри
  • table (str) – таблиця для перевірки

  • column (str) – колонка для перевірки

Тип повернення

bool

column_type(cr, table, column, sized=False)[source]

Повертає тип колонки, якщо він існує.

Параметри
  • table (str) – таблиця для перевірки

  • column (str) – колонка для перевірки

Тип повернення

SQL type of the column

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, дійсне лише якщо колонка є зовнішнім ключем.

Повертає

чи було створено колонку

Тип повернення

bool

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.

Параметри
  • table (str) – таблиця, з якої видалити обмеження

  • name (str) – назва обмеження, яке потрібно видалити

  • cascade (bool) – каскадне видалення обмежень

  • warn (bool) – використовувати рівень попередження під час реєстрації обмежень, що не знайдено, інакше використовувати рівень інформації

Повертає

чи було знято обмеження

Тип повернення

bool

class ColumnList(list_=(), quoted=())[source]

Інкапсулюйте список елементів, що представляють назви стовпців.

Результуючий об’єкт можна відобразити як рядок з початковою/кінцевою комою або аліасом.

Параметри
  • list (list(str)) – список назв колонок

  • quoted (list(str)) – список назв колонок у лапках, він має відповідати параметру list_

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 зі списку назв колонок, які можуть потребувати лапок.

Параметри

list (list(str)) – список назв колонок без лапок

using(leading_comma=KEEP_CURRENT, trailing_comma=KEEP_CURRENT, alias=KEEP_CURRENT)[source]

Налаштуйте параметри для відображення цього списку у вигляді рядка.

Параметри
  • leading_comma (bool) – чи відображати кому на початку цього списку

  • trailing_comma (bool) – чи відображати кінцеву кому

  • alias (str or None) – аліас таблиці колонок, аліас не додається, якщо встановлено значення None

Повертає

копія списку із заданими параметрами

Тип повернення

ColumnList

iter_unquoted()[source]

Перебираємо ітерації по необроблених назв колонок, без лапок.

Це корисно, якщо цитування виконується поза цим об’єктом. Також для отримання доступу до необроблених назв колонок, як у каталозі Postgres.

Повертає

ітератор для необроблених назв колонок

get_columns(cr, table, ignore=('id',))[source]

Повернути список колонок у таблиці.

Параметри
  • table (str) – назва таблиці, колонки якої отримуються

  • ignore (list(str)) – список назв колонок, які слід ігнорувати у списку повернення

Повертає

список назв колонок, присутніх у таблиці

Тип повернення

ColumnList

get_common_columns(cr, table1, table2, ignore=('id',))[source]

Повернути список колонок, присутніх в обох таблицях.

Параметри
  • table1 (str) – перша назва таблиці, колонки якої отримуються

  • table2 (str) – назва другої таблиці, колонки якої отримуються

  • ignore (list(str)) – список назв колонок, які слід ігнорувати у списку повернення

Повертає

список назв колонок, присутніх в обох таблицях

Тип повернення

ColumnList

rename_table(cr, old_table, new_table, remove_constraints=True)[source]

Перейменувати таблицю.

Ця функція перейменовує таблицю old_table на new_table, а також її первинний ключ (та послідовність), індекси та зовнішні ключі.

Параметри
  • old_table (str) – назва таблиці, яку потрібно перейменувати

  • new_table (str) – нова назва таблиці

Para bool remove_constraints

чи слід видаляти обмеження таблиці

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"

Повертає

назва щойно створеної/виправленої таблиці

Тип повернення

str

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 (str) – Версія Odoo повинна відповідати формату [saas~]X.Y, де X - це основна версія Odoo, saas~ необхідний лише тоді, коли Y не дорівнює нулю

Тип повернення

bool

version_between(a, b)[source]

Повертає, чи знаходиться поточна версія Odoo в діапазоні [a,b].

Див. також version_gte()

Примітка

Межі є інклюзивними.

Параметри
  • a (str) – Версія Odoo, нижня межа

  • b (str) – Версія Odoo, верхня межа

Тип повернення

bool

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.py

def my_util(cr):
    # do stuff

У myothermodule/16.0.1.0/post-migrate.py

from 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'>
Параметри
  • path (str) – відносний шлях до скрипта для імпорту у форматі $module/$version/$script-name .. примітка:: скрипт має бути доступний у шляху оновлення.

  • name (str or None) – назва, яку потрібно призначити повернутому модулю, візьміть назву з імпортованого файлу, якщо None

Повертає

модуль, створений з імпортованого скрипта оновлення

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.

Subclasses must implement:

  • For UpgradeCase:

    • prepare method: prepare data before upgrade,

    • check method: check data was correctly upgraded.

  • For IntegrityCase:

    • invariant method: 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:

  1. 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
    
  2. 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
    
  3. 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

UpgradeCase

IntegrityCase

$prepare_test_tag

upgrade.test_prepare

integrity_case.test_prepare

$check_test_tag

upgrade.test_check

integrity_test.test_check

Примітка

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_prepare will only run if the current Odoo version is in the range [next_major_version-1, version).

  • test_check will only run if the current Odoo version is in the range [version, next_major_version).

next_major_version is the next major version after version, e.g. for saas~17.2 it is 18.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:

  • prepare to set up data,

  • check to assert expectations after the upgrade.

The ORM can be used in these methods to perform the functional flow under test. The return value of prepare is persisted and passed as an argument to check. It must be JSON-serializable.

Примітка

Since prepare injects 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, use IntegrityCase tests 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:

  • invariant to return a JSON-serializable value representing the invariant to check.

The invariant method 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([])