@@ -445,6 +445,19 @@ def get_ids():
445445
446446 self ._ids = get_ids ()
447447
448+ def _values_query (self , query ):
449+ cr = self ._model .env .cr
450+ cr .execute (format_query (cr , "WITH query AS ({}) SELECT count(*) FROM query" , SQLStr (query )))
451+ size = cr .fetchone ()[0 ]
452+
453+ def get_values ():
454+ with named_cursor (cr , itersize = self ._chunk_size ) as ncr :
455+ ncr .execute (SQLStr (query ))
456+ for row in ncr .iterdict ():
457+ yield row
458+
459+ return size , get_values ()
460+
448461 def _browse (self , ids ):
449462 next (self ._end (), None )
450463 args = self ._cr_uid + (list (ids ),)
@@ -495,35 +508,47 @@ def caller(*args, **kwargs):
495508 self ._it = None
496509 return caller
497510
498- def create (self , values , ** kw ):
511+ def create (self , values = None , query = None , ** kw ):
499512 """
500513 Create records.
501514
502515 An alternative to the default `create` method of the ORM that is safe to use to
503516 create millions of records.
504517
505- :param list(dict) values: list of values of the records to create
518+ :param iterable(dict) values: iterable of values of the records to create
519+ :param int size: the no. of elements produced by values, required if values is a generator
520+ :param str query: alternative to values, SQL query that can produce them.
521+ *No* DML statements allowed. Only SELECT.
506522 :param bool multi: whether to use the multi version of `create`, by default is
507523 `True` from Odoo 12 and above
508524 """
509525 multi = kw .pop ("multi" , version_gte ("saas~11.5" ))
526+ size = kw .pop ("size" , None )
510527 if kw :
511528 raise TypeError ("Unknown arguments: %s" % ", " .join (kw ))
512529
513- if not values :
514- raise ValueError ("`create` cannot be called with an empty `values` argument " )
530+ if not ( values is None ) ^ ( query is None ) :
531+ raise ValueError ("`create` needs to be called using exactly one of `values` or `query` arguments " )
515532
516533 if self ._size :
517534 raise ValueError ("`create` can only called on empty `browse_record` objects." )
518535
519- ids = []
520- size = len (values )
536+ if query :
537+ size , values = self ._values_query (query )
538+
539+ if size is None :
540+ try :
541+ size = len (values )
542+ except TypeError :
543+ raise ValueError ("When passing a generator of values, the size kwarg is mandatory" )
544+
521545 it = chunks (values , self ._chunk_size , fmt = list )
522546 if self ._logger :
523547 sz = (size + self ._chunk_size - 1 ) // self ._chunk_size
524548 qualifier = "env[%r].create([:%d])" % (self ._model ._name , self ._chunk_size )
525549 it = log_progress (it , self ._logger , qualifier = qualifier , size = sz )
526550
551+ ids = []
527552 self ._patch = no_selection_cache_validation ()
528553 for sub_values in it :
529554 self ._patch .start ()
0 commit comments