@@ -974,11 +974,7 @@ def models(self, name='', transient=False):
974974 fld_transient = 'transient' if 'transient' in ir_model ._keys else 'osv_memory'
975975 domain = [('abstract' , '=' , False )] if 'abstract' in ir_model ._keys else [] # Odoo 19
976976 try :
977- if self .client .version_info < 8.0 :
978- recs = ir_model .search (domain )
979- models = ir_model .read (recs .ids , ('model' , fld_transient ))
980- else :
981- models = ir_model .search_read (domain , ('model' , fld_transient ))
977+ models = ir_model .search_read (domain , ('model' , fld_transient ))
982978 except ServerError :
983979 # Only Odoo 15 prevents non-admin user to retrieve models
984980 models = ir_model .get_available_models () if self .client .version_info >= 16.0 else {}
@@ -1578,8 +1574,6 @@ def drop_database(self, passwd, database):
15781574
15791575class BaseModel :
15801576
1581- ids = ()
1582-
15831577 def sudo (self , user = None ):
15841578 """Attach to the provided user, or Superuser."""
15851579 return self .with_env (self .env .sudo (user = user ))
@@ -1675,13 +1669,22 @@ def browse(self, ids=()):
16751669
16761670 def search (self , domain , ** kwargs ):
16771671 """Search for records in the `domain`."""
1678- ids = self ._execute ('search' , domain , ** kwargs )
1679- return RecordList (self , ids )
1672+ return RecordList ._prepared (self , domain , kwargs )
16801673
16811674 def search_count (self , domain = None ):
16821675 """Count the records in the `domain`."""
16831676 return self ._execute ('search_count' , domain or [])
16841677
1678+ def search_read (self , domain = None , fields = None , ** kwargs ):
1679+ """Combine search and read."""
1680+ fields , fmt = self ._parse_format (fields , browse = False )
1681+ if self .env .client .version_info < 8.0 :
1682+ ids = self ._execute ('search' , domain or [], ** kwargs )
1683+ res = self ._execute ('read' , ids , fields )
1684+ else :
1685+ res = self ._execute ('search_read' , domain or [], fields , ** kwargs )
1686+ return fmt (res )
1687+
16851688 def get (self , domain , * args , ** kwargs ):
16861689 """Return a single :class:`Record`.
16871690
@@ -1888,7 +1891,7 @@ def __init__(self, res_model, arg):
18881891 self .__dict__ .update (attrs )
18891892
18901893 def __repr__ (self ):
1891- ids = f'length={ len (self .ids )} ' if len (self .ids ) > 16 else self .id
1894+ ids = f'length={ len (self .ids )} ' if len (self .ids ) > 6 else self .id
18921895 return f"<{ self .__class__ .__name__ } '{ self ._name } ,{ ids } '>"
18931896
18941897 def __dir__ (self ):
@@ -2131,15 +2134,34 @@ class RecordList(BaseRecord):
21312134 to assign a single value to all the selected records.
21322135 """
21332136
2134- def __init__ (self , res_model , arg ):
2137+ def __init__ (self , res_model , arg , search = None ):
21352138 super ().__init__ (res_model , arg )
2136- idnames = arg or ()
2137- ids = list (idnames )
2138- for index , id_ in enumerate (arg ):
2139- if isinstance (id_ , (list , tuple )):
2140- ids [index ] = id_ = id_ [0 ]
2141- assert isinstance (id_ , int ), repr (id_ )
2142- self .__dict__ .update ({'id' : ids , 'ids' : ids , '_idnames' : idnames })
2139+ if search is None :
2140+ idnames = arg or ()
2141+ ids = list (idnames )
2142+ for index , id_ in enumerate (arg ):
2143+ if isinstance (id_ , (list , tuple )):
2144+ ids [index ] = id_ = id_ [0 ]
2145+ assert isinstance (id_ , int ), repr (id_ )
2146+ self .__dict__ .update ({'id' : ids , 'ids' : ids , '_idnames' : idnames , '_search_args' : None })
2147+ else :
2148+ self .__dict__ ['_search_args' ] = search
2149+
2150+ @classmethod
2151+ def _prepared (cls , res_model , domain , params ):
2152+ [domain ] = searchargs ((domain ,))
2153+ return cls (res_model , None , search = {'domain' : domain , ** params })
2154+
2155+ def refresh (self ):
2156+ """Reset :class:`RecordList` content."""
2157+ if self ._search_args :
2158+ for key in 'id' , 'ids' , '_idnames' :
2159+ self .__dict__ .pop (key , None )
2160+
2161+ def with_env (self , env ):
2162+ if 'id' in self .__dict__ :
2163+ return super ().with_env (env )
2164+ return RecordList (env [self ._name ], None , {** self ._search_args })
21432165
21442166 def read (self , fields = None ):
21452167 """Read the `fields` of the :class:`RecordList`.
@@ -2151,10 +2173,16 @@ def read(self, fields=None):
21512173
21522174 if fields == ['id' ]:
21532175 values = [{'id' : res_id } for res_id in self .ids ]
2154- elif self .id :
2155- values = self ._model .read (self .id , fields , order = True )
2176+ elif 'id' not in self .__dict__ :
2177+ params = {** self ._search_args }
2178+ domain = params .pop ('domain' )
2179+ values = self ._model .search_read (domain , fields , ** params )
2180+ ids = idnames = [val ['id' ] for val in values ]
2181+ if values and 'display_name' in values [0 ]:
2182+ idnames = [(val ['id' ], val ['display_name' ]) for val in values ]
2183+ self .__dict__ .update ({'id' : ids , 'ids' : ids , '_idnames' : idnames })
21562184 else :
2157- values = []
2185+ values = self . _model . read ( self . id , fields , order = True ) if self . id else []
21582186
21592187 return fmt (values )
21602188
@@ -2183,6 +2211,11 @@ def _external_id(self):
21832211 return [xml_ids .get (res_id , False ) for res_id in self .id ]
21842212
21852213 def __getattr__ (self , attr ):
2214+ if attr in ('id' , 'ids' , '_idnames' ):
2215+ params = {** self ._search_args }
2216+ ids = self ._execute ('search' , params .pop ('domain' ), ** params )
2217+ self .__dict__ .update ({'id' : ids , 'ids' : ids , '_idnames' : ids })
2218+ return self .__dict__ [attr ]
21862219 if attr in self ._model ._keys :
21872220 return self .read (attr )
21882221 if attr .startswith ('_' ):
0 commit comments