@@ -251,7 +251,7 @@ def wrapper(*args, **kwargs):
251251
252252
253253@no_selection_cache_validation
254- def recompute_fields (cr , model , fields , ids = None , logger = _logger , chunk_size = 256 , strategy = "auto" ):
254+ def recompute_fields (cr , model , fields , ids = None , logger = _logger , chunk_size = 256 , strategy = "auto" , query = None ):
255255 """
256256 Recompute field values.
257257
@@ -271,40 +271,54 @@ def recompute_fields(cr, model, fields, ids=None, logger=_logger, chunk_size=256
271271 :param str model: name of the model to recompute
272272 :param list(str) fields: list of the name of the fields to recompute
273273 :param list(int) or None ids: list of the IDs of the records to recompute, when `None`
274- recompute *all* records
274+ recompute *all* records, unless `query` is also set (see
275+ below)
275276 :param logger: logger used to report the progress
276277 :type logger: :class:`logging.Logger`
277278 :param int chunk_size: number of records per chunk - used to split the processing
278279 :param str strategy: strategy used to process the re-computation
280+ :param str query: query to get the IDs of records to recompute, it is an error to set
281+ both `ids` and `query`
279282 """
280- assert strategy in {"flush" , "commit" , "auto" }
283+ if strategy not in {"flush" , "commit" , "auto" }:
284+ raise ValueError ("Invalid strategy {!r}" .format (strategy ))
285+ if ids is not None and query is not None :
286+ raise ValueError ("Cannot set both `ids` and `query`" )
281287 Model = env (cr )[model ] if isinstance (model , basestring ) else model
282288 model = Model ._name
283289
284- def get_ids ():
285- if ids is not None :
286- for id_ in ids :
287- yield id_
290+ if ids is None :
291+ query = format_query (cr , "SELECT id FROM {} ORDER BY id" , table_of_model (cr , model )) if query is None else query
292+ cr .execute (query )
293+ count = cr .rowcount
294+ if count < 2 ** 21 : # avoid the overhead of a named cursor unless we have at least two chunks
295+ ids_ = (id_ for (id_ ,) in cr .fetchall ())
288296 else :
289- with named_cursor (cr , itersize = 2 ** 20 ) as ncr :
290- ncr .execute (format_query (cr , "SELECT id FROM {t} ORDER BY id" , t = table_of_model (cr , model )))
291- for (id_ ,) in ncr :
292- yield id_
293297
294- if ids is None :
295- cr .execute (format_query (cr , "SELECT COUNT(id) FROM {t}" , t = table_of_model (cr , model )))
296- (count ,) = cr .fetchone ()
298+ def get_ids ():
299+ with named_cursor (cr , itersize = 2 ** 20 ) as ncr :
300+ ncr .execute (query )
301+ for (id_ ,) in ncr :
302+ yield id_
303+
304+ ids_ = get_ids ()
297305 else :
298306 count = len (ids )
307+ ids_ = ids
308+
309+ if not count :
310+ return
311+
312+ _logger .info ("Computing fields %s of %r on %d records" , fields , model , count )
299313
300314 if strategy == "auto" :
301315 big_table = count > BIG_TABLE_THRESHOLD
302316 any_tracked_field = any (getattr (Model ._fields [f ], _TRACKING_ATTR , False ) for f in fields )
303317 strategy = "commit" if big_table and any_tracked_field else "flush"
304318
305319 size = (count + chunk_size - 1 ) / chunk_size
306- qual = "%s %d -bucket" % (model , chunk_size ) if chunk_size != 1 else model
307- for subids in log_progress (chunks (get_ids () , chunk_size , list ), logger , qualifier = qual , size = size ):
320+ qual = "{} {:d} -bucket" . format (model , chunk_size ) if chunk_size != 1 else model
321+ for subids in log_progress (chunks (ids_ , chunk_size , list ), logger , qualifier = qual , size = size ):
308322 records = Model .browse (subids )
309323 for field_name in fields :
310324 field = records ._fields [field_name ]
0 commit comments