Enable Dark Mode!
By: Risvana AR

How to Write Migration Scripts Using Open-Upgrade API?

The OpenUpgrade library contains all sorts of helper functions for pre and post-scripts, either in OpenUpgrade itself or in your own module's migration scripts (either for major or minor version upgrades).
Before migration, ensure that the OpenUpgrade source code contains scripts for migrating modules. If the script is not contained on the open upgrade, have some API for developing the migration script.
Let’s look at some general methods of OCA open upgrade.

General methods

openupgradelib.openupgrade.add_fields(env, field_spec):
This method adds everything needed to populate a new field in the database (SQL column, ir.model.fields entry, ir.model.data entry...).
Intended to run in a pre-migration script to pre-populate fields declared later in the module. Odoo always adds the XML-ID entry for version 12 and above.
Parameters: field_spec: list of tuples with the following expected elements in each tuple:
field name, model name, SQL table name, field type(many2many, many2one,integer, char, float, date, binary, datetime, boolean,HTML, one2many, many2one_reference, monetary, reference, selection, text, serialized,), SQL field type, module name, initialization value(optional)
openupgradelib.openupgrade.add_ir_model_fields(cr, columnspec)
New columns in ir_model_fields typically need to exist before the model is initialized, so they should be added to the raw SQL very early in the base module upgrade process. Do not use for fields with additional SQL restrictions such as Reference to another table or cascading constraint. However, write your own statements that take them into account.
Parameters: columnspec :(column name, column type)
openupgradelib.openupgrade.add_xmlid(cr, module, xmlid, model, res_id, noupdate=False)
Add an entry to ir_model_data. Usually called in a pre-migration.
openupgradelib.openupgrade.check_values_selection_field(cr, table_name, field_name, allowed_values)
Check if the field selection 'field_name' in table 'table_name' has only the value 'allowed_values'. Otherwise, return False and log an error. Returns True if yes.
openupgradelib.openupgrade.chunked(records, single=True)
A memory and performance-friendly way to iterate over potentially large datasets. Returns whole chunks or one record at a time. Do not nest calls to this method.
openupgradelib.openupgrade.column_exists(cr, table, column)
Checks if a specific column exists.
openupgradelib.openupgrade.convert_field_to_html(cr, table, field_name, html_field_name)
Convert field value to HTML value. 
openupgradelib.openupgrade.convert_to_company_dependent(env, model_name, origin_field_name, destination_field_name, model_table_name=None)
For each row of a particular table, the value of a particular field is set to a different "company-dependent" field within the same table. Useful if some fields in the model become "company-dependent" fields from release to release.
model_name, origin_field_name (Name of the field from which the values will be obtained.), destination_field_name (The name of the company-dependent field whose value is taken from origin_field_name. ), model_table_name (Name of the table. Optional. If not specified, the table name will be taken from the model.)
openupgradelib.openupgrade.copy_columns(cr, column_spec)
For copy table columns and calls in the pre-migration script.
column_spec: A hash with table keys whose values ??are lists of tuples. A tuple consists of (old_name, new_name, type). Use None for new_name to trigger conversion from old_name in get_legacy_name(). 
openupgradelib.openupgrade.copy_fields_multilang(cr, destination_model, destination_table, destination_columns, relation_column, source_model=None, source_table=None, source_columns=None, translations_only=False) 
Copy field contents, including translations.
Parameters: destination_model (The name of the target model to copy data to.), destination_table(List of column names in the destination_table that will receive the copied data.), relation_column(Name of a column in destination_table which points to IDs in source_table.), source_model(Name of the source model where the data will be copied from ), source_table(The name of the source table to copy data from.) ,source_columns (List of column names in the source_table that will provide the copied data.), translations_only(If True, it will only handle transferring translations.)
openupgradelib.openupgrade.cow_templates_mark_if_equal_to_upstream(cr, mark_colname=None)
Record which COW’d templates are equal to their upstream equivalents.
openupgradelib.openupgrade.cow_templates_replicate_upstream(cr, mark_colname=None)
Reset COW’d templates to their upstream equivalents. 
openupgradelib.openupgrade.date_to_datetime_tz(cr, table_name, user_field_name, date_field_name, datetime_field_name)
Consider the associated user's time zone when converting a date field to a datetime in a particular table. This function should be called in post-migration scripts.
Parameters: table_name(Name of the table where the field is), user_field_name(The name of the user field (res.users);), date_field_name(The name of the old date field.), datetime_field_name(The name of the new date field.)
openupgradelib.openupgrade.deactivate_workflow_transitions(cr, model, transitions=None)
Disable workflow transitions for a specific model's workflow. This may be required for automated workflow transitions when writing to objects through her ORM in post-migration steps. Returns a dictionary to use for reactivate_workflow_transitions.
Parameters: model (Model to disable workflow transitions on), transitions (List of ("module", "name") xmlid tuples of transitions to disable.)
openupgradelib.openupgrade.delete_record_translations(cr, module, xml_ids)
cleanup translations of specific records in a module.
Parameters: module (module name), xml_ids(A tuple or list of xml record IDs) 
openupgradelib.openupgrade.delete_records_safely_by_xml_id(env, xml_ids)
This will delete the record whose XML ID is passed as an argument in the safest way.
Parameters: xml_ids(List of XML-ID string identifiers of the records to remove.)
openupgradelib.openupgrade.delete_sql_constraint_safely(env, module, table, name)
Parameters: module(Module where the sql constraint was declared.), table(Table where the SQL constraint belongs.)
Analyze all existing active filters to see if they are still correct. Otherwise, it will be disabled to avoid click errors. Even worse is the case with default filters when opening models/actions.
openupgradelib.openupgrade.drop_columns(cr, column_spec)
Drop the column, but check if more columns exist. This includes the case of feature fields that may or may not be stored. Note that this may not be obvious: additional modules can control the memory properties of function fields. 
Parameters: table, field
Specifies versioned names for legacy tables/columns, etc. return. Use this function instead of custom names to avoid conflicts with future or past legacy tables/columns/etc. to avoid.
Parameters:original_name(The original name of the column)
openupgradelib.openupgrade.lift_constraints(cr, table, column)
Unconstrained the columns in the table. This is typically used in pre-migration scripts that reconcile Many2One field references where the target object has changed. If all goes well, the constraint will be recreated
openupgradelib.openupgrade.load_data(cr, module_name, filename, idref=None, mode='init')
Parameters: module_name, filename(The path to the filename, relative to the module directory.), idref(optional hash with ? id mapping cache?),
mode(one of ‘init’, ‘update’, ‘demo’, ‘init_no_create’. Always use 'init' to add new items from files marked 'noupdate'.). 
openupgradelib.openupgrade.logged_query(cr, query, args=None, skip_no_result=False)
Parameters: query (a query string suitable to pass to cursor.execute()), args(a list, tuple or dict passed as replacement value cursor.execute()), skip_no_result(If True, then logging details are only shown if there are affected records.) 
openupgradelib.openupgrade.logging(args_details=False, step=False)
This is a decorator for any sub-functions called in an OpenUpgrade script. (pre or post-migration script)
Parameters: args_details(If true, the argument details will be included in the log), step(Logging is done only once for each step.)
openupgradelib.openupgrade.m2o_to_x2m(cr, model, table, field, source_field)
Converts Many2one relationships to One2Many or Many2Many. Use rename_columns in the pre-migration script to preserve the old values ??of the columns, then call m2o_to_x2m in the post-migration script.
Parameters: model(The target model registry object), table(The source table), field(The new field name on the target model.), source_field(The (renamed) many2one column on the source table.)
openupgradelib.openupgrade.map_values(cr, source_column, target_column, mapping, model=None, table=None, write='sql')
Map old values ??to new values ??within the same model or table. Old values ??are probably from legacy columns. They were typically used in post-migration scripts.
Parameters: cr (The database cursor.), source_column (the database column that contains old values to be mapped), target_column(The database column or model field to which the new value will be written (if 'write' is 'orm'), mapping(List of tuples [(old value, new value)] Old value True represents “is set”, False “is not set.”), model (Used for writing if ‘write’ is ‘orm’, or to retrieve the table if ‘table’ is not given.), table (Database table used to query old values ??and write new values
(if ‘write’ is ‘SQL’)), write(Either ‘orm’ or ‘sql’. Note that old ids are always identified by an sql read.)
openupgradelib.openupgrade.merge_models(cr, old_model, new_model, ref_field) 
Update model references for models that have been merged into an existing model.
Parameters: old_model(old model name.), new_model (Destination model.), ref_field (name of the field in a new model that references the id of the old model.)
openupgradelib.openupgrade.message(cr, module, table, column, message, *args, **kwargs)
Parameters: module (Module name to which the message pertains), table( The model this message pertains to (may be false, but preferably not if "column" is defined), column(Columns related to this message)
openupgradelib.openupgrade.migrate(no_version=False, use_env=None, uid=None, context=None)
This is the decorator for the migrate() function. Set the no_version argument to True if the method should be accepted when the module is installed during migration.
Set the use_env argument if you want a v8+ environment instead of a plain cursor. Since version 10, this has been the default.
The uid and context arguments can be set when the environment is requested. For cursors, they are ignored.
openupgradelib.openupgrade.move_field_m2o(cr, pool, registry_old_model, field_old_model, m2o_field_old_model, registry_new_model, field_new_model, quick_request=True, compute_func=None, binary_field=False)
Used to move a Many2one field from one model to another. 
openupgradelib.openupgrade.reactivate_workflow_transitions(cr, transition_conditions)
Reactivates workflow transitions previously deactivated by activate_workflow_transitions.
Parameters: transition_conditions( Dictionary returned by activate_workflow_transitions.)
openupgradelib.openupgrade.remove_tables_fks(cr, tables)
For removing foreign keys declared in tables. 
Parameters: tables(List of tables where FKs are declared and tables where they are dropped. if the table does not exist, it is skipped.)
openupgradelib.openupgrade.rename_columns(cr, column_spec)
Renames the columns in the table.
Parameters: column_spec (A hash with table keys whose values ??are lists of tuples. A tuple consists of (old_name, new_name)  Use None for new_name to trigger conversion from old_name in get_legacy_name().)
openupgradelib.openupgrade.rename_fields(env, field_spec, no_deep=False)
Rename the field. Usually called in a prescript. WARNING: If you are using this in a base module, pass the no_deep argument with a value of True to avoid using the (not yet loaded) environment.
Parameters:  field_spec(a list of tuples with the following elements:  Model name, The name of the SQL table for the model, old field name, new field name.)
openupgradelib.openupgrade.rename_models(cr, model_spec)
Rename the model.  
Parameters: model_spec: a list of tuples (old model name, new model name).
openupgradelib.openupgrade.rename_property(cr, model, old_name, new_name)
Rename the old_name property owned by the model to the new_name. This should be done in a pre-migration script.
openupgradelib.openupgrade.rename_tables(cr, table_spec)
Rename the table. Usually called in a prescript. This function also renames the ID sequence if it exists and hasn't been changed in the same run.
Parameters: table_spec(List of tuples (old table name, new table name). Use None for new_name to trigger the conversion of old_name to the result of get_legacy_name().)
openupgradelib.openupgrade.rename_xmlids(cr, xmlids_spec, allow_merge=False)
Rename the XML ID. Usually called in a pre-migration. An example use case is when the identity module has changed. For example, in OpenERP 6, many res_group IDs were moved from other modules to module base (although they were still defined in their respective modules).
Parameters: xmlids_spec(A  list of tuples (old module.xmlid, new module.xmlid).), allow_merge (If the unique ID already exists, try to merge the records.)
openupgradelib.openupgrade.safe_unlink(records, do_raise=False)
Allow record unlink failure. 
Parameters: records (An iterable (not necessarily recordset) of records to unlink.), do_raise (Setting it to True causes exceptions to be thrown instead of being caught.)
openupgradelib.openupgrade.set_defaults(cr, pool, default_spec, force=False, use_orm=False)
Set default value.Useful for newly required fields. It uses ORM, i.e., calls from Postscript.
Parameters: pool(you can pass ‘env’ as well), default_spec (A hash keyed by model name. The value is a list of tuples (field, value). None has a special meaning as a value: it assigns a default value.)
force (Overwrite existing values. Used to assign non-default values ??(possibly for new columns). The ORM will assign default values ??declared in the model early in the process.) use_orm (When set to True, triggers writing default values ??using ORM instead of SQL clauses (default).)
openupgradelib.openupgrade.set_xml_ids_noupdate_value(env, module, xml_ids, value)
Set the xml_ids noupdate values in a module. 
Parameters: module(module name), xml_ids( a list or tuple of xml record IDs), value( True or False.)
openupgradelib.openupgrade.table_exists(cr, table)
Check whether a certain table or view exists. 
openupgradelib.openupgrade.update_field_multilang(records, field, method)
Update a field in all available languages in the database.
Parameters: records(Recordset for  updation), field (Field for  updation),
method( Method to execute to update the field.) 
openupgradelib.openupgrade.update_module_moved_fields(cr, model, moved_fields, old_module, new_module)
Updates modules for field definitions of Common tables have been moved from one module to another.
Parameters: cr(Database cursor), model (model name), moved_fields(list of moved fields), old_module(previous module of the fields),new_module( new module of the fields)
openupgradelib.openupgrade.update_module_moved_models(cr, model, old_module, new_module)
Update a module of a model definition in a common table that has been moved from one module to another. 
Parameters: cr(Database cursor),  model: (Model name), old_module( Previous module of the models), new_module (New module of the models)
openupgradelib.openupgrade.update_module_names(cr, namespec, merge_modules=False)
Handles changed module names and make necessary changes to related tables such as XML IDs, translations, etc.
Parameters: namespec (list of tuples of (old name, new name)
merge_modules (Specifies whether the operation should be a merge instead of just a rename. 
openupgradelib.openupgrade.update_workflow_workitems(cr, pool, ref_spec_actions)
Find all workflow elements in the target state and move them to the desired state.Run in pre-migration script.
Parameters: ref_spec_actions (List of tuples with a couple of workflow.action’s external ids. The first id is replaced with the second.)
openupgradelib.openupgrade.warn_possible_dataloss(cr, pool, old_module, fields)
Use this feature if the model's bay has been moved from the 'A' module to the 'B' module. (“B” depends on “A”). This function tests whether "B" is installed. If not, count the number of different values ??and possibly warn the user. Use ORMs. In other words, call it from Postscript.
old_module – the name of the old module, fields – list of dictionaries with the following keys: ‘table’: name of the table where the field is. ‘field’ : name of the field that is moving. ‘new_module’ : name of the new module 
For example :
From openupgradelib import openupgrade
def migrate(env, version):
openupgrade.convert_field_to_html(env.cr, "crm_lead", "description", "description")
ALTER TABLE crm_team_member
ALTER TABLE crm_team_member ALTER COLUMN assignment_max DROP DEFAULT;
Using openupgrade API, we can develop migration scripts for the module that does not have a migration script. You can also submit our scripts to  OCA Openupgrade.

If you need any assistance in odoo, we are online, please chat with us.


Leave a comment




Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635



Cybrosys Limited
Alpha House,
100 Borough High Street, London,
SE1 1LB, United Kingdom



Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.



Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message