← Back to team overview

openerp-community team mailing list archive

lp:~openerp-community/openobject-server/trunk-property-fields-using-get into lp:openobject-server

 

qdp (OpenERP) has proposed merging lp:~openerp-community/openobject-server/trunk-property-fields-using-get into lp:openobject-server.

Requested reviews:
  OpenERP Core Team (openerp)

For more details, see:
https://code.launchpad.net/~openerp-community/openobject-server/trunk-property-fields-using-get/+merge/67223

Enclosed, an improvement that targets to use the get() function of ir.property object when reading a property field (using a browse). Thanks to that, it will now be possible to force the company to use for property fields when processing flows.

While developing that feature, we had to clean and refactor the code of fnct_read and _get_defaults functions that were doing pretty nasty things to compute name_get on all the needed ids.

We also have added a function in tools (maybe that's not the perfect place?) that will factorize the code later on, on addons side. Check the example of use bellow for further information:
- .. for line in self.browse(cr, uid, ids, context=context):
+ .. set_company = tools.get_and_sort_by_field(cr, uid, obj=self, ids=ids, field='company_id', context=context)
+ .. for company_id, sol_ids in set_company.items():
+        ......ctx = context.copy()
+        ......ctx.update({'force_company': company_id})
+        ......for line in self.browse(cr, uid, sol_ids, context=ctx):

Thanks,
-- 
https://code.launchpad.net/~openerp-community/openobject-server/trunk-property-fields-using-get/+merge/67223
Your team OpenERP Community is subscribed to branch lp:~openerp-community/openobject-server/trunk-property-fields-using-get.
=== modified file 'openerp/osv/fields.py'
--- openerp/osv/fields.py	2011-07-05 08:53:22 +0000
+++ openerp/osv/fields.py	2011-07-07 16:41:30 +0000
@@ -1212,28 +1212,29 @@
         self._symbol_get = self._deserialize_func
         super(serialized, self).__init__(string=string, **args)
 
+import orm
 
 # TODO: review completly this class for speed improvement
 class property(function):
 
     def _get_default(self, obj, cr, uid, prop_name, context=None):
-        return self._get_defaults(obj, cr, uid, [prop_name], context=None)[0][prop_name]
+        return self._get_defaults(obj, cr, uid, [prop_name], context=None)[prop_name]
 
-    def _get_defaults(self, obj, cr, uid, prop_name, context=None):
+    def _get_defaults(self, obj, cr, uid, prop_names, context=None):
+        """
+          This function receives a list of property field name and returns a dictionary with
+           KEY: name of property fields
+           VALUE: the result of ir.property.get() function for res_id = False
+        """
         prop = obj.pool.get('ir.property')
-        domain = [('fields_id.model', '=', obj._name), ('fields_id.name','in',prop_name), ('res_id','=',False)]
-        ids = prop.search(cr, uid, domain, context=context)
         replaces = {}
-        default_value = {}.fromkeys(prop_name, False)
-        for prop_rec in prop.browse(cr, uid, ids, context=context):
-            if default_value.get(prop_rec.fields_id.name, False):
-                continue
-            value = prop.get_by_record(cr, uid, prop_rec, context=context) or False
-            default_value[prop_rec.fields_id.name] = value
-            if value and (prop_rec.type == 'many2one'):
-                replaces.setdefault(value._name, {})
-                replaces[value._name][value.id] = True
-        return default_value, replaces
+        default_value = {}.fromkeys(prop_names, False)
+        for prop_name in prop_names:
+            for value in [prop.get(cr, uid, prop_name, obj._name, context=context)]:
+                if isinstance(value, orm.browse_null):
+                    continue
+                default_value[prop_name] = value
+        return default_value
 
     def _get_by_id(self, obj, cr, uid, prop_name, ids, context=None):
         prop = obj.pool.get('ir.property')
@@ -1274,48 +1275,36 @@
             }, context=context)
         return False
 
-
-    def _fnct_read(self, obj, cr, uid, ids, prop_name, obj_dest, context=None):
+    def _fnct_read(self, obj, cr, uid, ids, prop_names, obj_dest, context=None):
         properties = obj.pool.get('ir.property')
-        domain = [('fields_id.model', '=', obj._name), ('fields_id.name','in',prop_name)]
-        domain += [('res_id','in', [obj._name + ',' + str(oid) for oid in  ids])]
-        nids = properties.search(cr, uid, domain, context=context)
-        default_val,replaces = self._get_defaults(obj, cr, uid, prop_name, context)
+        #get the default values (for res_id = False) for the property fields 
+        default_val = self._get_defaults(obj, cr, uid, prop_names, context)
 
+        #build the dictionary that will be returned
         res = {}
         for id in ids:
             res[id] = default_val.copy()
 
-        brs = properties.browse(cr, uid, nids, context=context)
-        for prop in brs:
-            value = properties.get_by_record(cr, uid, prop, context=context)
-            res[prop.res_id.id][prop.fields_id.name] = value or False
-            if value and (prop.type == 'many2one'):
-                # check existence as root, as seeing the name of a related
-                # object depends on access right of source document,
-                # not target, so user may not have access.
-                record_exists = obj.pool.get(value._name).exists(cr, 1, value.id)
-                if record_exists:
-                    replaces.setdefault(value._name, {})
-                    replaces[value._name][value.id] = True
-                else:
-                    res[prop.res_id.id][prop.fields_id.name] = False
-
-        for rep in replaces:
-            # search+name_get as root, as seeing the name of a related
-            # object depends on access right of source document,
-            # not target, so user may not have access.
-            nids = obj.pool.get(rep).search(cr, 1, [('id','in',replaces[rep].keys())], context=context)
-            replaces[rep] = dict(obj.pool.get(rep).name_get(cr, 1, nids, context=context))
-
-        for prop in prop_name:
-            for id in ids:
-                if res[id][prop] and hasattr(res[id][prop], '_name'):
-                    res[id][prop] = (res[id][prop].id , replaces[res[id][prop]._name].get(res[id][prop].id, False))
-
+        for prop in prop_names:
+            #if the property field is a m2o field, we will append the id of the value to name_get_list_ids
+            #in order to make a name_get in batch for all the ids needed.
+            name_get_list_ids = []
+            for id in ids:
+                #get the result of ir.property.get() for this res_id and save it in res if it's existing
+                obj_reference = obj._name + ',' + str(id)
+                value = properties.get(cr, uid, prop, obj._name, res_id=obj_reference, context=context)
+                if value:
+                    res[id][prop] = value
+                if isinstance(default_val[prop], orm.browse_record):
+                    name_get_list_ids.append(res[id][prop].id)
+            if isinstance(default_val[prop], orm.browse_record):
+                name_get_values = dict(obj.pool.get(default_val[prop]._name).name_get(cr, uid, name_get_list_ids, context=context))
+            #if the property field is a m2o, we need to return a tuple with (id, name)
+            for id in ids:
+                if res[id][prop] and isinstance(res[id][prop], orm.browse_record):
+                    res[id][prop] = (res[id][prop].id , name_get_values.get(res[id][prop].id, False))
         return res
 
-
     def _field_get(self, cr, uid, model_name, prop):
         if not self.field_id.get(cr.dbname):
             cr.execute('SELECT id \

=== modified file 'openerp/tools/misc.py'
--- openerp/tools/misc.py	2011-06-23 09:03:57 +0000
+++ openerp/tools/misc.py	2011-07-07 16:41:30 +0000
@@ -1387,6 +1387,22 @@
     a.start()
     return True
 
+def get_and_sort_by_field(cr, uid, obj, ids, field, context=None):
+    """
+     This function reads a field on several ids and build a dictionary {KEY:VALUE} with:
+       KEY: field value
+       VALUE: all the ids of obj that share the same value for that field
+    """
+    value_fields = obj.read(cr, uid, ids, [field],context=context)
+    res = {}
+    for item in value_fields:
+        key = item[field]
+        if isinstance(key,tuple):
+            key = key[0]
+        if not key in set_field:
+            res[key] = []
+        res[key].append(item['id'])
+    return res
 
 # port of python 2.6's attrgetter with support for dotted notation
 def resolve_attr(obj, attr):


Follow ups