import xmlrpclib
from psycopg2 import Binary
+import openerp
import openerp.netsvc as netsvc
import openerp.tools as tools
from openerp.tools.translate import _
_symbol_f = lambda x: x and 'True' or 'False'
_symbol_set = (_symbol_c, _symbol_f)
+ def __init__(self, string='unknown', required=False, **args):
+ super(boolean, self).__init__(string=string, required=required, **args)
+ if required:
+ warnings.warn("Making a boolean field `required` has no effect, as NULL values are "
+ "automatically turned into False", PendingDeprecationWarning, stacklevel=2)
+
class integer(_column):
_type = 'integer'
_symbol_c = '%s'
_symbol_set = (_symbol_c, _symbol_f)
_symbol_get = lambda self,x: x or 0
+ def __init__(self, string='unknown', required=False, **args):
+ super(integer, self).__init__(string=string, required=required, **args)
+ if required:
+ warnings.warn("Making an integer field `required` has no effect, as NULL values are "
+ "automatically turned into 0", PendingDeprecationWarning, stacklevel=2)
+
class integer_big(_column):
"""Experimental 64 bit integer column type, currently unused.
_symbol_set = (_symbol_c, _symbol_f)
_symbol_get = lambda self,x: x or 0
+ def __init__(self, string='unknown', required=False, **args):
+ super(integer_big, self).__init__(string=string, required=required, **args)
+ if required:
+ warnings.warn("Making an integer_big field `required` has no effect, as NULL values are "
+ "automatically turned into 0", PendingDeprecationWarning, stacklevel=2)
+
class reference(_column):
_type = 'reference'
+ _classic_read = False # post-process to handle missing target
+
def __init__(self, string, selection, size, **args):
_column.__init__(self, string=string, size=size, selection=selection, **args)
+ def get(self, cr, obj, ids, name, uid=None, context=None, values=None):
+ result = {}
+ # copy initial values fetched previously.
+ for value in values:
+ result[value['id']] = value[name]
+ if value[name]:
+ model, res_id = value[name].split(',')
+ if not obj.pool.get(model).exists(cr, uid, [int(res_id)], context=context):
+ result[value['id']] = False
+ return result
class char(_column):
_type = 'char'
_symbol_set = (_symbol_c, _symbol_f)
_symbol_get = lambda self,x: x or 0.0
- def __init__(self, string='unknown', digits=None, digits_compute=None, **args):
- _column.__init__(self, string=string, **args)
+ def __init__(self, string='unknown', digits=None, digits_compute=None, required=False, **args):
+ _column.__init__(self, string=string, required=required, **args)
self.digits = digits
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):
class many2many(_column):
"""Encapsulates the logic of a many-to-many bidirectional relationship, handling the
low-level details of the intermediary relationship table transparently.
+ A many-to-many relationship is always symmetrical, and can be declared and accessed
+ from either endpoint model.
+ If ``rel`` (relationship table name), ``id1`` (source foreign key column name)
+ or id2 (destination foreign key column name) are not specified, the system will
+ provide default values. This will by default only allow one single symmetrical
+ many-to-many relationship between the source and destination model.
+ For multiple many-to-many relationship between the same models and for
+ relationships where source and destination models are the same, ``rel``, ``id1``
+ and ``id2`` should be specified explicitly.
:param str obj: destination model
:param str rel: optional name of the intermediary relationship table. If not specified,
_type = 'many2many'
def __init__(self, obj, rel=None, id1=None, id2=None, string='unknown', limit=None, **args):
- """
+ """
"""
_column.__init__(self, string=string, **args)
self._obj = obj
def _sql_names(self, source_model):
"""Return the SQL names defining the structure of the m2m relationship table
-
+
:return: (m2m_table, local_col, dest_col) where m2m_table is the table name,
local_col is the name of the column holding the current model's FK, and
dest_col is the name of the column holding the destination model's FK, and
result = (value, dict_names[value])
if field_type == 'binary':
- if context.get('bin_size', False):
+ if context.get('bin_size'):
# client requests only the size of binary fields
result = get_nice_size(value)
- else:
+ elif not context.get('bin_raw'):
result = sanitize_binary_value(value)
if field_type in ("integer","integer_big") and value > xmlrpclib.MAXINT:
_columns = {
'foo_id': fields.many2one('my.foo', 'Foo'),
- 'bar': fields.related('frol', 'foo_id', type='char', string='Frol of Foo'),
+ 'bar': fields.related('foo_id', 'frol', type='char', string='Frol of Foo'),
}
"""
def _field_get2(self, cr, uid, obj, context=None):
if self._relations:
return
+ result = []
obj_name = obj._name
for i in range(len(self._arg)):
f = obj.pool.get(obj_name).fields_get(cr, uid, [self._arg[i]], context=context)[self._arg[i]]
- self._relations.append({
+ result.append({
'object': obj_name,
'type': f['type']
})
if f.get('relation',False):
obj_name = f['relation']
- self._relations[-1]['relation'] = f['relation']
+ result[-1]['relation'] = f['relation']
+ self._relations = result
# ---------------------------------------------------------
# Dummy fields
default_val = self._get_default(obj, cr, uid, prop_name, context)
- if id_val is not default_val:
+ property_create = False
+ if isinstance(default_val, openerp.osv.orm.browse_record):
+ if default_val.id != id_val:
+ property_create = True
+ elif default_val != id_val:
+ property_create = True
+
+ if property_create:
def_id = self._field_get(cr, uid, obj._name, prop_name)
company = obj.pool.get('res.company')
cid = company._company_default_get(cr, uid, obj._name, def_id,
self.field_id = {}
-def field_to_dict(self, cr, user, context, field):
+def field_to_dict(model, cr, user, field, context=None):
""" Return a dictionary representation of a field.
The string, help, and selection attributes (if any) are untranslated. This
res['fnct_inv_arg'] = field._fnct_inv_arg or False
res['func_obj'] = field._obj or False
if isinstance(field, many2many):
- res['related_columns'] = list((field._id1, field._id2))
- res['third_table'] = field._rel
+ (table, col1, col2) = field._sql_names(model)
+ res['related_columns'] = [col1, col2]
+ res['third_table'] = table
for arg in ('string', 'readonly', 'states', 'size', 'required', 'group_operator',
'change_default', 'translate', 'help', 'select', 'selectable'):
if getattr(field, arg):
res['selection'] = field.selection
else:
# call the 'dynamic selection' function
- res['selection'] = field.selection(self, cr, user, context)
+ res['selection'] = field.selection(model, cr, user, context)
if res['type'] in ('one2many', 'many2many', 'many2one', 'one2one'):
res['relation'] = field._obj
res['domain'] = field._domain
res['context'] = field._context
+ if isinstance(field, one2many):
+ res['relation_field'] = field._fields_id
+
return res