← Back to team overview

openerp-india team mailing list archive

[Bug 1018908] [NEW] fields.function stored with multi argument and mixed integer/manyone types

 

Public bug reported:

This is quite a tricky bug that requires 2 fields.function stored in
database, linked with a 'multi' argument and of two different types:
integer and many2one. Something like that:

_columns = {
  'm2o_field_id': fields.function(_get_infos, method=True, type='many2one', relation='some.object', string='some string', store=True),
  'integer_field': fields.function(_get_infos, method=True, type='integer', string='some other string', store=True),
}

Lets say, _store_set_values(self, cr, uid, ids, fields, context):" is
called with fields= ['m2o_field_id', 'integer_field'], ids = [my_id]

in orm.py, line 3824, you have:

        todo = {}
        keys = []
        for f in fields:
            if self._columns[f]._multi not in keys:
                keys.append(self._columns[f]._multi)
            todo.setdefault(self._columns[f]._multi, [])
            todo[self._columns[f]._multi].append(f)
        for key in keys:
            val = todo[key]
            if key:
                # uid == 1 for accessing objects having rules defined on store fields
                result = self._columns[val[0]].get(cr, self, ids, val, 1, context=context)

so val will contain either  ['m2o_field_id', 'integer_field'] or
['integer_field', 'm2o_field_id'] depending on the order they are called

and the fields.get function will be called with val[0] which is either
an integer field or a many2one field.

Now if you go to the get function of fields.function, you have this type of code:
fields.py, line 817
        if self._type == "many2one" :
            # Filtering only integer/long values if passed
            res_ids = [x for x in res.values() if x and isinstance(x, (int,long))]

            if res_ids:
                obj_model = obj.pool.get(self._obj)
                dict_names = dict(obj_model.name_get(cr, user, res_ids, context))
                for r in res.keys():
                    if res[r] and res[r] in dict_names:
                        res[r] = (res[r], dict_names[res[r]])

        if self._type == "integer":
            for r in res.keys():
                # Converting value into string so that it does not affect XML-RPC Limits
                if isinstance(res[r],dict): # To treat integer values with _multi attribute
                    for record in res[r].keys():
                        res[r][record] = str(res[r][record])
                else:
                    res[r] = str(res[r])

Either way, the function _get_infos will return something like that:
{my_id:{
'integer_field': 200,
'm2o_field_id': 42,
}}
but the result in _store_set_values will have either (depending on the order):
- if val[0] is a many2one:
result ={my_id:{
'integer_field': 200,
'm2o_field_id': 42,
}} (no_action)
or
- if val[0] is an integer:
result ={my_id:{
'integer_field': '200',
'm2o_field_id': '42',
}} (integer field transforms into string)

And in _store_set_values, you have:
in orm.py, line 3834

for id, value in result.items():
#some code
    for v in value:
        if v not in val:
            continue
        if self._columns[v]._type in ('many2one', 'one2one'):
            try:
                value[v] = value[v][0]
            except:
                pass

So we will store either:
{
'integer_field': 200,
'm2o_field_id': 42,
} => OK
or
{
'integer_field': '200',
'm2o_field_id': '4', #instead of 42
} => KO

depending on the order...

server 6.0, revno 3626

** Affects: openobject-server
     Importance: Undecided
         Status: New

** Description changed:

- This is quite a tricky bug that 2 fields.function stored in database,
- linked with a 'multi' argument and of two different types: integer and
- many2one. Something like that:
+ This is quite a tricky bug that requires 2 fields.function stored in
+ database, linked with a 'multi' argument and of two different types:
+ integer and many2one. Something like that:
  
  _columns = {
-   'm2o_field_id': fields.function(_get_infos, method=True, type='many2one', relation='some.object', string='some string', store=True),
-   'integer_field': fields.function(_get_infos, method=True, type='integer', string='some other string', store=True),
+   'm2o_field_id': fields.function(_get_infos, method=True, type='many2one', relation='some.object', string='some string', store=True),
+   'integer_field': fields.function(_get_infos, method=True, type='integer', string='some other string', store=True),
  }
  
  Lets say, _store_set_values(self, cr, uid, ids, fields, context):" is
  called with fields= ['m2o_field_id', 'integer_field'], ids = [my_id]
  
  in orm.py, line 3824, you have:
  
-         todo = {}
-         keys = []
-         for f in fields:
-             if self._columns[f]._multi not in keys:
-                 keys.append(self._columns[f]._multi)
-             todo.setdefault(self._columns[f]._multi, [])
-             todo[self._columns[f]._multi].append(f)
-         for key in keys:
-             val = todo[key]
-             if key:
-                 # uid == 1 for accessing objects having rules defined on store fields
-                 result = self._columns[val[0]].get(cr, self, ids, val, 1, context=context)
+         todo = {}
+         keys = []
+         for f in fields:
+             if self._columns[f]._multi not in keys:
+                 keys.append(self._columns[f]._multi)
+             todo.setdefault(self._columns[f]._multi, [])
+             todo[self._columns[f]._multi].append(f)
+         for key in keys:
+             val = todo[key]
+             if key:
+                 # uid == 1 for accessing objects having rules defined on store fields
+                 result = self._columns[val[0]].get(cr, self, ids, val, 1, context=context)
  
  so val will contain either  ['m2o_field_id', 'integer_field'] or
  ['integer_field', 'm2o_field_id'] depending on the order they are called
  
  and the fields.get function will be called with val[0] which is either
  an integer field or a many2one field.
  
  Now if you go to the get function of fields.function, you have this type of code:
- fields.py, line 817 
-         if self._type == "many2one" :
-             # Filtering only integer/long values if passed
-             res_ids = [x for x in res.values() if x and isinstance(x, (int,long))]
+ fields.py, line 817
+         if self._type == "many2one" :
+             # Filtering only integer/long values if passed
+             res_ids = [x for x in res.values() if x and isinstance(x, (int,long))]
  
-             if res_ids:
-                 obj_model = obj.pool.get(self._obj)
-                 dict_names = dict(obj_model.name_get(cr, user, res_ids, context))
-                 for r in res.keys():
-                     if res[r] and res[r] in dict_names:
-                         res[r] = (res[r], dict_names[res[r]])
+             if res_ids:
+                 obj_model = obj.pool.get(self._obj)
+                 dict_names = dict(obj_model.name_get(cr, user, res_ids, context))
+                 for r in res.keys():
+                     if res[r] and res[r] in dict_names:
+                         res[r] = (res[r], dict_names[res[r]])
  
-         if self._type == "integer":
-             for r in res.keys():
-                 # Converting value into string so that it does not affect XML-RPC Limits
-                 if isinstance(res[r],dict): # To treat integer values with _multi attribute
-                     for record in res[r].keys():
-                         res[r][record] = str(res[r][record])
-                 else:
-                     res[r] = str(res[r])
+         if self._type == "integer":
+             for r in res.keys():
+                 # Converting value into string so that it does not affect XML-RPC Limits
+                 if isinstance(res[r],dict): # To treat integer values with _multi attribute
+                     for record in res[r].keys():
+                         res[r][record] = str(res[r][record])
+                 else:
+                     res[r] = str(res[r])
  
  Either way, the function _get_infos will return something like that:
  {my_id:{
  'integer_field': 200,
  'm2o_field_id': 42,
  }}
  but the result in _store_set_values will have either (depending on the order):
  - if val[0] is a many2one:
  result ={my_id:{
  'integer_field': 200,
  'm2o_field_id': 42,
  }} (no_action)
  or
  - if val[0] is an integer:
  result ={my_id:{
  'integer_field': '200',
  'm2o_field_id': '42',
  }} (integer field transforms into string)
  
  And in _store_set_values, you have:
  in orm.py, line 3834
  
  for id, value in result.items():
  #some code
-     for v in value:
-         if v not in val:
-             continue
-         if self._columns[v]._type in ('many2one', 'one2one'):
-             try:
-                 value[v] = value[v][0]
-             except:
-                 pass
+     for v in value:
+         if v not in val:
+             continue
+         if self._columns[v]._type in ('many2one', 'one2one'):
+             try:
+                 value[v] = value[v][0]
+             except:
+                 pass
  
  So we will store either:
  {
  'integer_field': 200,
  'm2o_field_id': 42,
  } => OK
  or
  {
  'integer_field': '200',
  'm2o_field_id': '4', #instead of 42
  } => KO
  
  depending on the order...
  
  server 6.0, revno 3626

-- 
You received this bug notification because you are a member of OpenERP
Indian Team, which is subscribed to OpenERP Server.
https://bugs.launchpad.net/bugs/1018908

Title:
  fields.function stored with multi argument and mixed integer/manyone
  types

Status in OpenERP Server:
  New

Bug description:
  This is quite a tricky bug that requires 2 fields.function stored in
  database, linked with a 'multi' argument and of two different types:
  integer and many2one. Something like that:

  _columns = {
    'm2o_field_id': fields.function(_get_infos, method=True, type='many2one', relation='some.object', string='some string', store=True),
    'integer_field': fields.function(_get_infos, method=True, type='integer', string='some other string', store=True),
  }

  Lets say, _store_set_values(self, cr, uid, ids, fields, context):" is
  called with fields= ['m2o_field_id', 'integer_field'], ids = [my_id]

  in orm.py, line 3824, you have:

          todo = {}
          keys = []
          for f in fields:
              if self._columns[f]._multi not in keys:
                  keys.append(self._columns[f]._multi)
              todo.setdefault(self._columns[f]._multi, [])
              todo[self._columns[f]._multi].append(f)
          for key in keys:
              val = todo[key]
              if key:
                  # uid == 1 for accessing objects having rules defined on store fields
                  result = self._columns[val[0]].get(cr, self, ids, val, 1, context=context)

  so val will contain either  ['m2o_field_id', 'integer_field'] or
  ['integer_field', 'm2o_field_id'] depending on the order they are
  called

  and the fields.get function will be called with val[0] which is either
  an integer field or a many2one field.

  Now if you go to the get function of fields.function, you have this type of code:
  fields.py, line 817
          if self._type == "many2one" :
              # Filtering only integer/long values if passed
              res_ids = [x for x in res.values() if x and isinstance(x, (int,long))]

              if res_ids:
                  obj_model = obj.pool.get(self._obj)
                  dict_names = dict(obj_model.name_get(cr, user, res_ids, context))
                  for r in res.keys():
                      if res[r] and res[r] in dict_names:
                          res[r] = (res[r], dict_names[res[r]])

          if self._type == "integer":
              for r in res.keys():
                  # Converting value into string so that it does not affect XML-RPC Limits
                  if isinstance(res[r],dict): # To treat integer values with _multi attribute
                      for record in res[r].keys():
                          res[r][record] = str(res[r][record])
                  else:
                      res[r] = str(res[r])

  Either way, the function _get_infos will return something like that:
  {my_id:{
  'integer_field': 200,
  'm2o_field_id': 42,
  }}
  but the result in _store_set_values will have either (depending on the order):
  - if val[0] is a many2one:
  result ={my_id:{
  'integer_field': 200,
  'm2o_field_id': 42,
  }} (no_action)
  or
  - if val[0] is an integer:
  result ={my_id:{
  'integer_field': '200',
  'm2o_field_id': '42',
  }} (integer field transforms into string)

  And in _store_set_values, you have:
  in orm.py, line 3834

  for id, value in result.items():
  #some code
      for v in value:
          if v not in val:
              continue
          if self._columns[v]._type in ('many2one', 'one2one'):
              try:
                  value[v] = value[v][0]
              except:
                  pass

  So we will store either:
  {
  'integer_field': 200,
  'm2o_field_id': 42,
  } => OK
  or
  {
  'integer_field': '200',
  'm2o_field_id': '4', #instead of 42
  } => KO

  depending on the order...

  server 6.0, revno 3626

To manage notifications about this bug go to:
https://bugs.launchpad.net/openobject-server/+bug/1018908/+subscriptions


Follow ups

References