""" return a low-level field object corresponding to `self` """
assert self.store
- # some columns are registry-dependent, like float fields (digits);
- # duplicate them to avoid sharing between registries
+ # determine column parameters
_logger.debug("Create fields._column for Field %s", self)
args = {}
for attr, prop in self.column_attrs:
args['relation'] = self.comodel_name
return fields.property(**args)
- if isinstance(self.column, fields.function):
- # it is too tricky to recreate a function field, so for that case,
- # we make a stupid (and possibly incorrect) copy of the column
- return copy(self.column)
+ if self.column:
+ # let the column provide a valid column for the given parameters
+ return self.column.new(**args)
return getattr(fields, self.type)(**args)
class Reference(Selection):
type = 'reference'
- size = 128
+ size = None
def __init__(self, selection=None, string=None, **kwargs):
super(Reference, self).__init__(selection=selection, string=string, **kwargs)
def _setup(self, env):
super(Reference, self)._setup(env)
- assert isinstance(self.size, int), \
+ assert isinstance(self.size, (NoneType, int)), \
"Reference field %s with non-integer size %r" % (self, self.size)
_related_size = property(attrgetter('size'))
super(Id, self).__init__(type='integer', string=string, **kwargs)
def to_column(self):
- """ to_column() -> fields._column
-
- Whatever
- """
return fields.integer('ID')
def __get__(self, record, owner):
self.help = args.get('help', '')
self.priority = priority
self.change_default = change_default
- self.ondelete = ondelete.lower() if ondelete else None # defaults to 'set null' in ORM
+ self.ondelete = ondelete.lower() if ondelete else 'set null'
self.translate = translate
self._domain = domain
self._context = context
if not self._classic_write or self.deprecated:
self._prefetch = False
+ def new(self, **args):
+ """ return a column like `self` with the given parameters """
+ # memory optimization: reuse self whenever possible; you can reduce the
+ # average memory usage per registry by 10 megabytes!
+ return self if self.same_parameters(args) else type(self)(**args)
+
+ def same_parameters(self, args):
+ dummy = object()
+ return all(
+ # either both are falsy, or they are equal
+ (not val1 and not val) or (val1 == val)
+ for key, val in args.iteritems()
+ for val1 in [getattr(self, key, getattr(self, '_' + key, dummy))]
+ )
+
def to_field(self):
""" convert column `self` to a new-style field """
from openerp.fields import Field
# synopsis: digits_compute(cr) -> (precision, scale)
self.digits_compute = digits_compute
+ def new(self, **args):
+ # float columns are database-dependent, so always recreate them
+ return type(self)(**args)
+
def to_field_args(self):
args = super(float, self).to_field_args()
args['digits'] = self.digits_compute or self.digits
self._symbol_f = type_class._symbol_f
self._symbol_set = type_class._symbol_set
+ def new(self, **args):
+ # HACK: function fields are tricky to recreate, simply return a copy
+ import copy
+ return copy.copy(self)
+
def to_field_args(self):
args = super(function, self).to_field_args()
if self._type in ('float',):