[IMP] fields.sparse: custom sparse field creation now working + handle deleted resour...
authorOlivier Dony <odo@openerp.com>
Thu, 22 Dec 2011 18:24:05 +0000 (19:24 +0100)
committerOlivier Dony <odo@openerp.com>
Thu, 22 Dec 2011 18:24:05 +0000 (19:24 +0100)
bzr revid: odo@openerp.com-20111222182405-425rzyl6idg9aocu

openerp/addons/base/ir/ir_model.py
openerp/osv/fields.py

index 4531c12..88ad218 100644 (file)
@@ -21,6 +21,7 @@
 import logging
 import re
 import time
+import types
 
 from osv import fields,osv
 import netsvc
@@ -32,13 +33,12 @@ from tools.translate import _
 import pooler
 
 def _get_fields_type(self, cr, uid, context=None):
-    cr.execute('select distinct ttype,ttype from ir_model_fields')
-    field_types = cr.fetchall()
-    field_types_copy = field_types
-    for types in field_types_copy:
-        if not hasattr(fields,types[0]):
-            field_types.remove(types)
-    return field_types
+    return sorted([(k,k) for k,v in fields.__dict__.iteritems()
+                      if type(v) == types.TypeType
+                      if issubclass(v, fields._column)
+                      if v != fields._column
+                      if not v._deprecated
+                      if not issubclass(v, fields.function)])
 
 def _in_modules(self, cr, uid, ids, field_name, arg, context=None):
     #pseudo-method used by fields.function in ir.model/ir.model.fields
@@ -207,7 +207,11 @@ class ir_model_fields(osv.osv):
         'view_load': fields.boolean('View Auto-Load'),
         'selectable': fields.boolean('Selectable'),
         'modules': fields.function(_in_modules, method=True, type='char', size=128, string='In modules', help='List of modules in which the field is defined'),
-        'serialization_field_id': fields.many2one('ir.model.fields', 'Serialization Field', domain = "[('ttype','=','serialized')]", ondelete='cascade'),
+        'serialization_field_id': fields.many2one('ir.model.fields', 'Serialization Field', domain = "[('ttype','=','serialized')]",
+                                                  ondelete='cascade', help="If set, this field will be stored in the sparse "
+                                                                           "structure of the serialization field, instead "
+                                                                           "of having its own database column. This cannot be "
+                                                                           "changed after creation."),
     }
     _rec_name='field_description'
     _defaults = {
@@ -300,7 +304,7 @@ class ir_model_fields(osv.osv):
         if context and context.get('manual',False):
             vals['state'] = 'manual'
 
-        #For the moment renaming a sparse field or changing the storing system is not allowed. This will be done later
+        #For the moment renaming a sparse field or changing the storing system is not allowed. This may be done later
         if 'serialization_field_id' in vals or 'name' in vals:
             for field in self.browse(cr, user, ids, context=context):
                 if 'serialization_field_id' in vals and field.serialization_field_id.id != vals['serialization_field_id']:
index 6fef850..53b8d30 100644 (file)
@@ -45,6 +45,7 @@ import openerp
 import openerp.netsvc as netsvc
 import openerp.tools as tools
 from openerp.tools.translate import _
+from openerp.tools import float_round, float_repr
 import json
 
 def _symbol_set(symb):
@@ -74,6 +75,9 @@ class _column(object):
     _symbol_set = (_symbol_c, _symbol_f)
     _symbol_get = None
 
+    # used to hide a certain field type in the list of field types
+    _deprecated = False
+
     def __init__(self, string='unknown', required=False, readonly=False, domain=None, context=None, states=None, priority=0, change_default=False, size=None, ondelete=None, translate=False, select=False, manual=False, **args):
         """
 
@@ -167,6 +171,7 @@ class integer_big(_column):
     _symbol_f = lambda x: int(x or 0)
     _symbol_set = (_symbol_c, _symbol_f)
     _symbol_get = lambda self,x: x or 0
+    _deprecated = True
 
     def __init__(self, string='unknown', required=False, **args):
         super(integer_big, self).__init__(string=string, required=required, **args)
@@ -230,17 +235,20 @@ class float(_column):
     def __init__(self, string='unknown', digits=None, digits_compute=None, required=False, **args):
         _column.__init__(self, string=string, required=required, **args)
         self.digits = digits
+        # synopsis: digits_compute(cr) ->  (precision, scale)
         self.digits_compute = digits_compute
         if required:
             warnings.warn("Making a float field `required` has no effect, as NULL values are "
                           "automatically turned into 0.0", PendingDeprecationWarning, stacklevel=2)
 
-
     def digits_change(self, cr):
         if self.digits_compute:
-            t = self.digits_compute(cr)
-            self._symbol_set=('%s', lambda x: ('%.'+str(t[1])+'f') % (__builtin__.float(x or 0.0),))
-            self.digits = t
+            self.digits = self.digits_compute(cr)
+        if self.digits:
+            precision, scale = self.digits
+            self._symbol_set = ('%s', lambda x: float_repr(float_round(__builtin__.float(x or 0.0),
+                                                                       precision_digits=scale),
+                                                           precision_digits=scale))
 
 class date(_column):
     _type = 'date'
@@ -270,6 +278,7 @@ class datetime(_column):
 
 class time(_column):
     _type = 'time'
+    _deprecated = True
     @staticmethod
     def now( *args):
         """ Returns the current time in a format fit for being a
@@ -343,6 +352,7 @@ class one2one(_column):
     _classic_read = False
     _classic_write = True
     _type = 'one2one'
+    _deprecated = True
 
     def __init__(self, obj, string='unknown', **args):
         warnings.warn("The one2one field doesn't work anymore", DeprecationWarning)
@@ -991,11 +1001,14 @@ class function(_column):
             self._symbol_set = integer._symbol_set
 
     def digits_change(self, cr):
-        if self.digits_compute:
-            t = self.digits_compute(cr)
-            self._symbol_set=('%s', lambda x: ('%.'+str(t[1])+'f') % (__builtin__.float(x or 0.0),))
-            self.digits = t
-
+        if self._type == 'float':
+            if self.digits_compute:
+                self.digits = self.digits_compute(cr)
+            if self.digits:
+                precision, scale = self.digits
+                self._symbol_set = ('%s', lambda x: float_repr(float_round(__builtin__.float(x or 0.0),
+                                                                           precision_digits=scale),
+                                                               precision_digits=scale))
 
     def search(self, cr, uid, obj, name, args, context=None):
         if not self._fnct_search:
@@ -1255,10 +1268,20 @@ class sparse(function):
             serialized = getattr(record, self.serialization_field)
             results[record.id] = {}
             for field_name in field_names:
-                if obj._columns[field_name]._type in ['one2many']:
-                    value = serialized.get(field_name, [])
-                else:
-                    results[record.id].update(field_name=value)
+                field_type = obj._columns[field_name]._type
+                value = serialized.get(field_name, False)
+                if field_type in ('one2many','many2many'):
+                    value = value or []
+                    if value:
+                        # filter out deleted records as superuser
+                        relation_obj = obj.pool.get(self.relation)
+                        value = relation_obj.exists(cr, openerp.SUPERUSER_ID, value)
+                if type(value) in (int,long) and field_type == 'many2one':
+                    relation_obj = obj.pool.get(self.relation)
+                    # check for deleted record as superuser
+                    if not relation_obj.exists(cr, openerp.SUPERUSER_ID, [value]):
+                        value = False
+                results[record.id][field_name] = value
         return results
 
     def __init__(self, serialization_field, **kwargs):
@@ -1267,8 +1290,6 @@ class sparse(function):
      
 
 
-
-
 # ---------------------------------------------------------
 # Dummy fields
 # ---------------------------------------------------------