Upgrade utils¶
Upgrade utils is a library that contains helper functions to facilitate the writing of upgrade scripts. This library, used by Odoo for the upgrade scripts of standard modules, provides reliability and helps speed up the upgrade process:
The helper functions help make sure the data is consistent in the database.
It takes care of indirect references of the updated records.
Allows calling functions and avoid writing code, saving time and reducing development risks.
Helpers allow to focus on what is important for the upgrade and not think of details.
Installation¶
Clone the Upgrade utils repository locally and start
odoo
with the src
directory prepended to the --upgrade-path
option.
$ ./odoo-bin --upgrade-path=/path/to/upgrade-util/src,/path/to/other/upgrade/script/directory [...]
On platforms where you do not manage Odoo yourself, you can install this library via pip
:
$ python3 -m pip install git+https://github.com/odoo/upgrade-util@master
On Odoo.sh it is recommended to add it to the requirements.txt
of
the custom repository. For this, add the following line inside the file:
odoo_upgrade @ git+https://github.com/odoo/upgrade-util@master
Using upgrade utils¶
Once installed, the following packages are available for the upgrade scripts:
odoo.upgrade.util
: the helper itself.odoo.upgrade.testing
: base TestCase classes.
To use it in upgrade scripts, simply import it:
from odoo.upgrade import util
def migrate(cr, version):
# Rest of the script
Now, the helper functions are available to be called through util
.
Util functions¶
Upgrade utils provides many useful functions to ease the upgrade process. Here, we describe some of the most useful ones. Refer to the util folder for the comprehensive declaration of helper functions.
Note
The cr
parameter in util functions always refers to the database cursor. Pass the one
received as a parameter in migrate()
. Not all functions need this parameter.
Modules¶
Utility functions for module-level operations.
In most cases module operations (rename, merge, remove, …) should be performed in a
base
script. The reason is that once the base
module is upgraded, all the information
regarding modules should be already set in the DB for the upgrade process to function
correctly.
- odoo.upgrade.util.modules.modules_installed(cr, *modules)[source]¶
Return whether all given modules are installed.
Note
In the context of upgrades a module is considered as installed if it is marked for upgrade, or for installation; even if they are not yet fully installed.
- odoo.upgrade.util.modules.module_installed(cr, module)[source]¶
Return whether a module is installed.
See
modules_installed()
.
- odoo.upgrade.util.modules.uninstall_module(cr, module)[source]¶
Uninstall and remove all records owned by a module.
- Parameters
module (str) – name of the module to uninstall
- odoo.upgrade.util.modules.uninstall_theme(cr, theme, base_theme=None)[source]¶
Uninstall a theme module and remove it from websites.
- Parameters
Warning
This function can only be used in
post-
scripts ofwebsite
module as it relies on the ORM.See
remove_theme()
anduninstall_module()
.
- odoo.upgrade.util.modules.remove_module(cr, module)[source]¶
Completely remove a module.
This operation is equivalent to uninstall and removal of all references to the module - no trace of it is left in the database.
- Parameters
module (str) – name of the module to remove
Warning
Since this function removes all data associated to the module. Ensure to reassign records before calling this function.
- odoo.upgrade.util.modules.remove_theme(cr, theme, base_theme=None)[source]¶
Uninstall a theme module.
Warning
This function can only be used in
post-
scripts.See
remove_module()
anduninstall_theme()
.
- odoo.upgrade.util.modules.rename_module(cr, old, new)[source]¶
Rename a module and all references to it.
- odoo.upgrade.util.modules.merge_module(cr, old, into, update_dependers=True)[source]¶
Merge a module into another.
This function moves all references and records from the source module to the destination module.
Warning
This functions does not remove any record, but it removes xml_ids from the source module with a conflicting name in the destination module.
- odoo.upgrade.util.modules.force_install_module(cr, module, if_installed=None)[source]¶
Force the ORM to install a module.
- odoo.upgrade.util.modules.force_upgrade_of_fresh_module(cr, module, init=True)[source]¶
Force the execution of upgrade scripts for a module that is being installed.
Standard Odoo doesn’t run upgrade scripts when a module is being installed. This makes sense because, technically speaking, the module is not being upgraded. Still, it happens that a (new) module needs to perform some operations for it to be correctly installed, like grabbing data from another module. This is common when a module is functionally split into several ones.
- Parameters
Being in init mode has the side effect of not respecting noupdate flags, in XML file nor in
ir_model_data
.
- odoo.upgrade.util.modules.move_model(cr, model, from_module, to_module, move_data=False, keep=())[source]¶
Move a model from one module to another.
- Parameters
This function can be called for moving overrides of a model to another module. As it cannot distinguish between source model or inherited model, it raises an exception if the destination module isn’t installed.
Models¶
Utility functions for modifying models.
Model operations are best done in pre-
script of the involved modules.
- odoo.upgrade.util.models.remove_model(cr, model, drop_table=True, ignore_m2m=())[source]¶
Remove a model and its references from the database.
Some required indirect references to the model are replaced by the unknown model - an empty model that serves as placeholder for gone models.
- odoo.upgrade.util.models.delete_model(cr, model, drop_table=True, ignore_m2m=())[source]¶
Remove a model and its references from the database.
Some required indirect references to the model are replaced by the unknown model - an empty model that serves as placeholder for gone models.
- odoo.upgrade.util.models.merge_model(cr, source, target, drop_table=True, fields_mapping=None, ignore_m2m=())[source]¶
Merge a model into another one.
This function moves all the references from
source
model intotarget
model and removessource
model and its references. By default, only the fields with the same name in both models are moved from source to target, optionally a mapping with differently named fields can be provided.Warning
This function does not move the records from
source
model totarget
model.- Parameters
source (str) – name of the model to be merged
target (str) – name of the destination model to merge into
drop_table (bool) – whether to drop the table of the source model
fields_mapping (dict or None) – mapping of field names from source to target model, when
None
only fields with same name are movedignore_m2m (list(str) or str) – list of m2m tables ignored to remove from source model.
Fields¶
Utility functions for modifying model fields.
Field operations are best done in pre-
script of the involved modules. In some cases a
preliminary operation could be done in pre and finished in post. A common example is to
remove a field in pre- keeping its column, later used in post when the column is finally
dropped.
- odoo.upgrade.util.fields.remove_field(cr, model, fieldname, cascade=False, drop_column=True, skip_inherit=())[source]¶
Remove a field and its references from the database.
This function also removes the field from inheriting models, unless exceptions are specified in
skip_inherit
. When the field is stored we can choose to not drop the column.- Parameters
model (str) – model name of the field to remove
fieldname (str) – name of the field to remove
cascade (bool) – whether the field column(s) are removed in
CASCADE
modedrop_column (bool) – whether the field’s column is dropped
skip_inherit (list(str) or str) – list of inheriting models to skip the removal of the field, use
"*"
to skip all
- odoo.upgrade.util.fields.move_field_to_module(cr, model, fieldname, old_module, new_module, skip_inherit=())[source]¶
Move a field from one module to another.
This functions updates all references to a specific field, switching from the source module to the destination module. It avoid data removal after the registry is fully loaded. The field in inheriting models are also moved unless skipped.
- Parameters
model (str) – name of the owner model of the field to move
fieldname (str) – name of the field to move
old_module (str) – source module name from which the field is moved
new_module (str) – target module name into which the field is moved
skip_inherit (list(str) or str) – list of inheriting models for which the field is not to be moved, use
"*"
to skip all
- odoo.upgrade.util.fields.rename_field(cr, model, old, new, update_references=True, domain_adapter=None, skip_inherit=())[source]¶
Rename a field and its references from
old
tonew
on the givenmodel
.The field is updated in all inheriting models, except for models specified in
skip_inherit
.This functions also updates references, indirect or direct ones, including filters, server actions, related fields, emails, dashboards, domains, and many more. See
update_field_usage()
For the update of domains a special adapter function can be used. The default adapter just replaces
old
bynew
in each domain leaf. Refer toadapt_domains()
for information about domain adapters.- Parameters
model (str) – model name of the field to rename
old (str) – current name of the field to rename
new (str) – new name of the field to rename
update_references (bool) – whether to update all references
domain_adapter (function) – adapter to use for domains, see
adapt_domains()
skip_inherit (list(str) or str) – models to skip when renaming the field in inheriting models, use
"*"
to skip all
- odoo.upgrade.util.fields.invert_boolean_field(cr, model, old, new, skip_inherit=())[source]¶
Rename a boolean field and invert its value.
- odoo.upgrade.util.fields.change_field_selection_values(cr, model, field, mapping, skip_inherit=())[source]¶
Replace references of values of a selection field.
This function replaces all references to selection values according to a mapping. Domains are also updated.
- Parameters
model (str) – model name of the selection field to update
field (str) – name of the selection field to update
mapping (dict) – selection values to update, key values are replaced by their corresponding values in the mapping
skip_inherit (list(str) or str) – list of inheriting models to skip in the update of the selection values, use
"*"
to skip all
- odoo.upgrade.util.fields.update_field_usage(cr, model, old, new, domain_adapter=None, skip_inherit=())[source]¶
Replace all references to the field
old
bynew
in different places.- Search in:
ir_filters
ir_exports_line
ir_act_server
mail_alias
ir_ui_view_custom (dashboard)
domains (using
domain_adapter
)related fields
This function can be used to replace the usage of a field by another. Domains are updated using the
domain_adapter
. By default the domain adapter just replacesold
bynew
in domain leaves. Seeadapt_domains()
for more information about domain adapters.- Parameters
model (str) – model name of the field
old (str) – source name of the field to replace
new (str) – target name of the field to set
domain_adapter (function) – adapter to use for domains, see
adapt_domains()
skip_inherit (list(str) or str) – models to skip when renaming the field in inheriting models, use
"*"
to skip all
Records¶
Utility functions for record-level operations.
- odoo.upgrade.util.records.remove_view(cr, xml_id=None, view_id=None, silent=False, key=None)[source]¶
Remove a view and all its descendants.
This function recursively deletes the given view and its inherited views, as long as they are part of a module. It will fail as soon as a custom view exists anywhere in the hierarchy. It also removes multi-website COWed views.
- Parameters
xml_id (str) – optional, the xml_id of the view to remove
view_id (int) – optional, the ID of the view to remove
silent (bool) – whether to show in the logs disabled custom views
key (str or None) – key used to detect multi-website COWed views, if
None
then set toxml_id
if provided, otherwise set to the xml_id referencing the view with IDview_id
if any
Warning
Either
xml_id
orview_id
must be set. Specifying both will raise an error.
- odoo.upgrade.util.records.edit_view(cr, xmlid=None, view_id=None, skip_if_not_noupdate=True, active='auto')[source]¶
Context manager to edit a view’s arch.
This function returns a context manager that may yield a parsed arch of a view as an etree Element. Any changes done in the returned object will be written back to the database upon exit of the context manager, updating also the translated versions of the arch. Since the function may not yield, use
skippable_cm()
to avoid errors.with util.skippable_cm(), util.edit_view(cr, "xml.id") as arch: arch.attrib["string"] = "My Form"
To select the target view to edit use either
xmlid
orview_id
, not both.When the view is identified by
view_id
, the arch is always yielded if the view exists, with disregard to anynoupdate
flag it may have associated. Whenxmlid
is set, if the viewnoupdate
flag isFalse
then the arch will not be yielded unlessskip_if_not_noupdate
is set toFalse
. Ifnoupdate
isTrue
, the view will be yielded for edit.If the
active
argument isTrue
orFalse
, theactive
flag of the view will be set accordingly.Note
If
active
is “auto” (default value), the view will be activated if selected viaxmlid
and left untouched if selected viaview_id
.- Parameters
xmlid (str) – optional, xml_id of the view edit
view_id (int) – optional, ID of the view to edit
skip_if_not_noupdate (bool) – whether to force the edit of views requested via
xmlid
parameter even if they are flagged asnoupdate=True
, ignored ifview_id
is setactive (bool or None or "auto") – active flag value to set. Unchanged when
None
.
- Returns
a context manager that yields the parsed arch, upon exit the context manager writes back the changes.
- odoo.upgrade.util.records.remove_record(cr, name)[source]¶
Remove a record and its references corresponding to the given xml_id.
- Parameters
name (str) – record xml_id, under the format
module.name
- odoo.upgrade.util.records.is_changed(cr, xmlid, interval='1 minute')[source]¶
Return whether a record was changed.
This function checks if a record was changed before the current upgrade start time. See
upgrade-util/src/base/0.0.0/pre-00-upgrade-start.py
This utility will return a false positive on xmlids of records that match the following conditions:
Have been updated in an upgrade preceding the current one
Have not been updated in the current upgrade
- odoo.upgrade.util.records.if_unchanged(cr, xmlid, callback, interval='1 minute', **kwargs)[source]¶
Run
callback
if a record is unchanged.This function will run a
callback
when the referred record is unchanged. Thexmlid
and any extra parameter, but notinterval
, will be passed to thecallback
. In case the record was changed it will be marked asnoupdate=True
. See alsois_changed()
andforce_noupdate()
.This function is useful to take an action only when a record hasn’t been updated, a common example is to force an update from XML even if the record was
noupdate=True
util.if_unchanged(cr, "mymodule.myrecord", util.update_record_from_xml)
- Parameters
- odoo.upgrade.util.records.rename_xmlid(cr, old, new, noupdate=None, on_collision='fail')[source]¶
Rename an external identifier (
xml_id
) of a record.A rename cannot happen when the target name already exists on the database. In such cases there are two options to control how this function behaves:
fail
: raise an exception and prevent renamingmerge
: rename the external identifier, remove the old one, and replace references. Seereplace_record_references_batch()
Note
This function does not remove records, it only updates xml_ids.
- Parameters
old (str) – current xml_id of the record, under the format
module.name
new (str) – new xml_id of the record, under the format
module.name
noupdate (bool or None) – value to set on the
noupdate
flag of the xml_id, ignored ifNone
on_collision (str) – how to proceed if the xml_id already exists, the options are
merge
orfail
(default)
- Returns
the ID of the record referenced by the new xml_id,
None
when the record doesn’t exist- Return type
int or
None
- odoo.upgrade.util.records.ref(cr, xmlid)[source]¶
Return the id corresponding to the given xml_id.
- Parameters
xml_id (str) – record xml_id, under the format
module.name
- Returns
ID of the referenced record,
None
if not found.- Return type
int or
None
- odoo.upgrade.util.records.force_noupdate(cr, xmlid, noupdate=True, warn=False)[source]¶
Update the
noupdate
flag of a record.
- odoo.upgrade.util.records.ensure_xmlid_match_record(cr, xmlid, model, values)[source]¶
Ensure an xml_id references a record with specific values.
This function ensures the record pointed by an xml_id matches the values for the fields specified in the
values
parameter. When the xmlid exist but it points to a record that doesn’t match the values, the xmlid is updated to point to a record that matches the values if one is found. If the xmlid doesn’t exist, it is created with the found record. When no matching record is found, nothing is done. In all cases the referenced record, after a possible update, of the xml_id is returned.- Parameters
- Returns
the ID of the matched record,
None
if no record found- Return type
Tip
This function is useful when migrating in-database records into a custom module, to create the xml_ids before the module is updated and avoid duplication.
- odoo.upgrade.util.records.update_record_from_xml(cr, xmlid, reset_write_metadata=True, force_create=True, from_module=None, reset_translations=(), ensure_references=False)[source]¶
Update a record based on its definition in the Data Files.
This function ignores the
noupdate
flag on the record. It searches in all XML files from the manifest of the module in the xmlid, or thefrom_module
parameter if set, for a matching definition. When found, it forces the ORM to update the record as in the specs in the data file.Optionally this function can reset the translations of some fields.
- Parameters
xmlid (str) – record xml_id, under the format
module.name
reset_write_metadata (bool) – whether to update the
write_date
of the recordforce_create (bool) – whether the record is created if it does not exist
from_module (str) – name of the module from which to update the record, necessary only when the specs are in a different module than the one in the xml_id
reset_translations (set(str)) – field names whose translations get reset
ensure_references (bool) – whether referred records via
ref
XML attributes should also be updated.
Warning
This functions uses the ORM, therefore it can only be used after all models referenced in the data specs of the record are already loaded. In practice this means that this function should be used in
post-
orend-
scripts.Note
The standard behavior of ORM is to create the record if it doesn’t exist, including its xml_id. That will happen on this function as well.
- odoo.upgrade.util.records.delete_unused(cr, *xmlids, **kwargs)[source]¶
Remove unused records.
This function will remove records pointed by
xmlids
only if they are not referenced from any table.Note
The records that cannot be removed are set as
noupdate=True
.- Parameters
- Returns
list of ids of removed records, if any
- Return type
- odoo.upgrade.util.records.replace_record_references_batch(cr, id_mapping, model_src, model_dst=None, replace_xmlid=True, ignores=())[source]¶
Replace all references to records.
This functions replaces all references, direct or indirect to records of
model_src
by the corresponding records in the mapping. If the target model of the mapping is not the same as the source one, thenmodel_dst
parameter must be set.- Parameters
id_mapping (dict(int, int)) – mapping of IDs to replace, key value is replaced by the mapped value
model_src (str) – name of the source model of the records to replace
model_dst (str) – name of the target model of the records to replace, if
None
the target is assumed the same as the sourcereplace_xmlid (bool) – whether to replace the references in xml_ids pointing to the source records
ignores (list(str)) – list of table names to skip when updating the referenced values
- odoo.upgrade.util.records.replace_in_all_jsonb_values(cr, table, column, old, new, extra_filter=None)[source]¶
Replace values in JSONB columns.
This function replaces
old
bynew
in JSONB values. It is useful for replacing values in all translations of translated fields.- Parameters
table (str) – table name where the values are to be replaced
column (str) – column name where the values are to be replaced
old (str) – original value to replace, can be a simple term (str) or a Postgres regular expression wrapped by
PGRegexp
new (str) – new value to set, can be a simple term or a expression using
<number>
notation to refer to captured groups ifold
is a regexp expressionextra_filter (str) – extra
WHERE
compatible clause to filter the values to update, must use thet
alias for the table, it can also include{parallel_filter}
to execute the query in parallel, seeexplode_execute()
ORM¶
Utility functions to perform operations via the ORM.
The functions on this module allow to use the ORM safely during upgrades. They enhance or patch the ORM such that it can handle high volumes of data in a performant way. In some cases totally different alternatives to the ORM’s own functions are provided. The functions on this module work along the ORM of all supported versions.
- odoo.upgrade.util.orm.env(cr)[source]¶
Create a new environment.
Warning
This function does not empty the cache maintained on the cursor for superuser with an empty environment. A call to
invalidate_cache
may be necessary every time data is modified directly in the database.- Returns
the new environment
- Return type
- odoo.upgrade.util.orm.recompute_fields(cr, model, fields, ids=None, logger=<Logger odoo.upgrade.util.orm (WARNING)>, chunk_size=256, strategy='auto')[source]¶
Recompute field values.
This function will recompute fields of a model restricted to a set of records - or all. The re-computation is not done on all records at the same time. It is split in batches (chunks). This avoids performance issues, and, in the worse cases, failures due to
MemoryError
. After each chunk is processed the data is sent back to the database according to one of the following strategies:flush: use the
flush
method of the ORMcommit:
commit
the cursor - also flushauto: pick the best alternative between the two above given the number of records to compute and the presence of tracked fields.
The commit strategy is less prone to cause a
MemoryError
for a huge volume of data.- Parameters
model (str) – name of the model to recompute
fields (list(str)) – list of the name of the fields to recompute
ids (list(int) or None) – list of the IDs of the records to recompute, when
None
recompute all recordslogger (
logging.Logger
) – logger used to report the progresschunk_size (int) – number of records per chunk - used to split the processing
strategy (str) – strategy used to process the re-computation
- class odoo.upgrade.util.orm.iter_browse(model, *args, **kw)[source]¶
Iterate over recordsets.
The
callable
object returned by this class can be used as an iterator that loads records by chunks (into arecordset
). After each chunk is exhausted their data is sent back to the database - flushed or committed - and a new chunk is loaded.This class allows to run code like:
for record in env['my.model'].browse(ids): record.field1 = val env['my.model'].browse(ids)._compute_field2() env['my.model'].create(values)
in a performant way while also avoiding
MemoryError
, even whenids
orvalues
have millions of entries. The alternative using this class would be: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)
- Parameters
model (
odoo.model.Model
) – the model to iteratechunk_size (int) – number of records to load in each iteration chunk,
200
by defaultlogger (
logging.Logger
) – logger used to report the progress, by default_logger
strategy (str) – whether to
flush
orcommit
on each chunk, default isflush
- Returns
the object returned by this class can be used to iterate, or call any model method, safely on millions of records.
See also
env()
- odoo.upgrade.util.domains.adapt_domains(cr, model, old, new, adapter=None, skip_inherit=(), force_adapt=False)[source]¶
Replace
old
bynew
in domains usingmodel
and inheriting models.adapter
is a callback function to adapt leaves. Adapter functions must take three arguments and return a domain that substitutes the original leaf. The arguments are:leaf
: a domain leaf which is atuple
of the form(left, op, right)
in_or
: a boolean, whenTrue
it means the leaf is part of an OR ("|"
) domain, otherwise it is part of an AND ("&"
) domainnegated
: a boolean, whenTrue
it means that the leaf is negated ("!"
)
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
is called only on leaves that use theold
field ofmodel
as last part of theleft
part of leaves, unlessforce_adapt
isTrue
. In the latter case the adapter is called if the field appears anywhere in the path, useful for relational fields only.The domains returned by an adapter do not need to have the
old
field replaced bynew
in theleft
part of the input leaf. The replace will be done anyway to the whole domain returned by the adapter. The usual purpose of theadapter
is to modify the operator and theright
part of the input leaf. Whenadapter
is not set only the replacement takes place.Example
When replacing
"field1"
by"field2"
, the following happens:("foo.bar.baz.field1", "=", 1)
gets adapted only if the record pointed to byfoo.bar.baz
is of the requestedmodel
.("foo.field1.baz", "=", 1)
is not adapted even iffoo
points tomodel
, unlessforce_adapt
isTrue
, becausefield1
is not the last part ofleft
in this leaf.
Note
This function will replace domains in all standard domain fields. Including filters, dashboards, and standard fields known to represent a domain.
- Parameters
model (str) – name of the model for which to adapt the domains
old (str) – name of the field to be adapted
new (str) – name of the field that should replace
old
adapter (function) – adapter for leaves
skip_inherit (list(str)) – list of inheriting model names to don’t adapt (skip)
force_adapt (bool) – when
True
, run theadapter
on all leaves havingnew
inleft
part of the leaf (path), useful when deleting a field (in which casenew
is ignored).
SQL¶
Utility functions for interacting with PostgreSQL.
- class odoo.upgrade.util.pg.PGRegexp[source]¶
Wrapper for semantic meaning of parameters: this string is a Postgres regular expression.
- odoo.upgrade.util.pg.parallel_execute(cr, queries, logger=<Logger odoo.upgrade.util.pg (WARNING)>)[source]¶
Execute queries in parallel.
Example
util.parallel_execute(cr, [util.format_query(cr, "REINDEX TABLE {}", t) for t in tables])
Tip
If looking to speedup a single query, see
explode_execute()
.- Parameters
- Returns
the sum of
cr.rowcount
for each query run- Return type
Warning
Due to the nature of
cr.rowcount
, the return value of this function may represent an underestimate of the real number of affected records. For instance, when some records are deleted/updated as a result of anondelete
clause, they won’t be taken into account.As a side effect, the cursor will be committed.
Note
If a concurrency issue occurs, the failing queries will be retried sequentially.
- odoo.upgrade.util.pg.format_query(cr, query, *args, **kwargs)[source]¶
Safely format a query.
The
str
arguments to this function are assumed to be SQL identifiers. They are wrapped in double quotes before being expanded usingstr.format()
. Any other psycopg2.sql.Composable are also allowed. This includesColumnList
, see alsoget_columns()
Example
>>> util.format_query(cr, "SELECT {0} FROM {table}", "id", table="res_users") SELECT "id" FROM "res_users"
- Parameters
query (str) – query to format, can use brackets
{}
as instr.format()
- odoo.upgrade.util.pg.explode_execute(cr, query, table, alias=None, bucket_size=10000, logger=<Logger odoo.upgrade.util.pg (WARNING)>)[source]¶
Execute a query in parallel.
The query is split by buckets of ids, then processed in parallel by workers. If the query does not include the special
{parallel_filter}
value, it is added to the lastWHERE
clause, possibly also adding it if none found. When the query already has the filter nothing is done. The filter always expands to the splitting strategy. The split is done into buckets where no more thanbucket_size
IDs are updated on each individual query.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", )
- Parameters
query (str) – the query to execute.
table (str) – name of the main table of the query, used to split the processing
alias (str) – alias used for the main table in the query
bucket_size (int) – size of the buckets of ids to split the processing
logger (
logging.Logger
) – logger used to report the progress
- Returns
the sum of
cr.rowcount
for each query run- Return type
Warning
It’s up to the caller to ensure the queries do not update the same records in different buckets. It is advised to never use this function for
DELETE
queries on tables with self references due to the potentialON DELETE
effects. For more details seeparallel_execute()
.
- odoo.upgrade.util.pg.column_type(cr, table, column)[source]¶
Return the type of a column, if it exists.
- odoo.upgrade.util.pg.create_column(cr, table, column, definition, **kwargs)[source]¶
Create a column.
This function will create the column only if it doesn’t exist. It will log an error if the existing column has different type. If
fk_table
is set, it will ensure the foreign key is setup, updating if necessary, with the righton_delete_action
if any is set.- Parameters
table (str) – table of the new column
column (str) – name of the new column
definition (str) – column type of the new column
default (bool) – default value to set on the new column
fk_table (bool) – if the new column if a foreign key, name of the foreign table
on_delete_action (str) –
ON DELETE
clause, defaultNO ACTION
, only valid if the column is a foreign key.
- Returns
whether the column was created
- Return type
- odoo.upgrade.util.pg.remove_constraint(cr, table, name, cascade=False, warn=True)[source]¶
Remove a table constraint.
This function removes the constraint
name
fromtable
. It also removes records fromir_model_constraint
and its xml_ids. It logs not found constraints.Note
If there is no constraint
name
, this function will attempt to remove{table}_{name}
, the latter is the default name the ORM uses for constraints created from_sql_constraints
.- Parameters
- Returns
whether the constraint was removed
- Return type
- class odoo.upgrade.util.pg.ColumnList(list_=(), quoted=())[source]¶
Encapsulate a list of elements that represent column names.
The resulting object can be rendered as string with leading/trailing comma or an alias.
- Parameters
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'
Note
This class is better used via
get_columns()
- odoo.upgrade.util.pg.get_columns(cr, table, ignore=('id',))[source]¶
Return a list of columns in a table.
- Parameters
- Returns
a list of column names present in the table
- Return type
Misc¶
Miscellaneous standalone functions.
- odoo.upgrade.util.misc.version_gte(version)[source]¶
Return whether currently running Odoo version is greater or equal to
version
.This function is useful for conditional execution in an upgrade script that applies to multiple versions, e.g.
0.0.0
scripts.
- odoo.upgrade.util.misc.version_between(a, b)[source]¶
Return whether currently running Odoo version is in the range
[a,b]
.See also
version_gte()
Note
The bounds are inclusive.
- odoo.upgrade.util.misc.expand_braces(s)[source]¶
Expand braces in the input.
Example
>>> util.expand_braces("a_{this,that}_b") ['a_this_b', 'a_that_b']
- Parameters
s (str) – string to expand, must contain precisely one pair of braces.
- Returns
expanded input
- odoo.upgrade.util.misc.import_script(path, name=None)[source]¶
Import an upgrade script.
This function allows to import functions from other upgrade scripts into the current one.
Example
In
mymodule/15.0.1.0/pre-migrate.py
def my_util(cr): # do stuff
In
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
This function returns a Python
module
.>>> 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'>
- Parameters
- Returns
a module created from the imported upgrade script
- odoo.upgrade.util.misc.skippable_cm()[source]¶
Return a context manager to allow another context manager to not yield.
See
edit_view()
for an example usage.
- odoo.upgrade.util.misc.chunks(iterable, size, fmt=None)[source]¶
Split
iterable
into chunks ofsize
and wrap each chunk usingfmt
function.This function is useful for splitting huge input data into smaller chunks that can be processed independently.
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'
- Parameters
iterable (iterable) – iterable object to split
size (int) – chunk size
fmt (function) – function to apply to each chunk, when
None
is passedfmt
becomes"".join
ifiterable
is a string, otherwiseiter
- Returns
a generator that iterates over the result of
fmt
applied to each chunk