import copy
import datetime
import logging
+import warnings
import operator
import pickle
import re
class browse_record(object):
logger = netsvc.Logger()
- def __init__(self, cr, uid, id, table, cache, context=None, list_class = None, fields_process={}):
+ def __init__(self, cr, uid, id, table, cache, context=None, list_class=None, fields_process=None):
'''
table : the object (inherited from orm)
context : dictionary with an optional context
'''
- if not context:
+ if fields_process is None:
+ fields_process = {}
+ if context is None:
context = {}
self._list_class = list_class or browse_record_list
self._cr = cr
def read_group(self, cr, uid, domain, fields, groupby, offset=0, limit=None, context=None):
raise NotImplementedError(_('The read_group method is not implemented on this object !'))
- def _field_create(self, cr, context={}):
+ def _field_create(self, cr, context=None):
+ if context is None:
+ context = {}
cr.execute("SELECT id FROM ir_model WHERE model=%s", (self._name,))
if not cr.rowcount:
cr.execute('SELECT nextval(%s)', ('ir_model_id_seq',))
vals['relation'], bool(vals['view_load']),
vals['select_level'], bool(vals['readonly']), bool(vals['required']), bool(vals['selectable']), vals['relation_field'], vals['model'], vals['name']
))
- continue
+ break
cr.commit()
- def _auto_init(self, cr, context={}):
- self._field_create(cr, context)
+ def _auto_init(self, cr, context=None):
+ self._field_create(cr, context=context)
def __init__(self, cr):
if not self._name and not hasattr(self, '_inherit'):
if not self._table:
self._table = self._name.replace('.', '_')
- def browse(self, cr, uid, select, context=None, list_class=None, fields_process={}):
+ def browse(self, cr, uid, select, context=None, list_class=None, fields_process=None):
"""
Fetch records as objects allowing to use dot notation to browse fields and relations
:rtype: object or list of objects requested
"""
- if not context:
- context = {}
self._list_class = list_class or browse_record_list
cache = {}
# need to accepts ints and longs because ids coming from a method
if isinstance(select, (int, long)):
return browse_record(cr, uid, select, self, cache, context=context, list_class=self._list_class, fields_process=fields_process)
elif isinstance(select, list):
- return self._list_class([browse_record(cr, uid, id, self, cache, context=context, list_class=self._list_class, fields_process=fields_process) for id in select], context)
+ return self._list_class([browse_record(cr, uid, id, self, cache, context=context, list_class=self._list_class, fields_process=fields_process) for id in select], context=context)
else:
return browse_null()
lines = []
data = map(lambda x: '', range(len(fields)))
+ done = []
for fpos in range(len(fields)):
- done = []
f = fields[fpos]
if f:
r = row
fields2 = map(lambda x: (x[:i+1]==f[:i+1] and x[i+1:]) \
or [], fields)
if fields2 in done:
- break
+ if [x for x in fields2 if x]:
+ break
done.append(fields2)
for row2 in r:
lines2 = self.__export_row(cr, uid, row2, fields2,
for key in self.pool._sql_error.keys():
if key in e[0]:
msg = self.pool._sql_error[key]
+ if hasattr(msg, '__call__'):
+ msg = msg(cr, uid, [res_id,], context=context)
break
return (-1, res, 'Line ' + str(counter) +' : ' + msg, '')
if isinstance(e, osv.orm.except_orm):
return (done, 0, 0, 0)
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
+ """
+ Read records with given ids with the given fields
+
+ :param cr: database cursor
+ :param user: current user id
+ :param ids: id or list of the ids of the records to read
+ :param fields: optional list of field names to return (default: all fields would be returned)
+ :type fields: list (example ['field_name_1', ...])
+ :param context: optional context dictionary - it may contains keys for specifying certain options
+ like ``context_lang``, ``context_tz`` to alter the results of the call.
+ A special ``bin_size`` boolean flag may also be passed in the context to request the
+ value of all fields.binary columns to be returned as the size of the binary instead of its
+ contents. This can also be selectively overriden by passing a field-specific flag
+ in the form ``bin_size_XXX: True/False`` where ``XXX`` is the name of the field.
+ Note: The ``bin_size_XXX`` form is new in OpenERP v6.0.
+ :return: list of dictionaries((dictionary per record asked)) with requested field values
+ :rtype: [{‘name_of_the_field’: value, ...}, ...]
+ :raise AccessError: * if user has no read rights on the requested object
+ * if user tries to bypass access rules for read on the requested object
+
+ """
raise NotImplementedError(_('The read method is not implemented on this object !'))
def get_invalid_fields(self, cr, uid):
# Check presence of __call__ directly instead of using
# callable() because it will be deprecated as of Python 3.0
if hasattr(msg, '__call__'):
- txt_msg, params = msg(self, cr, uid, ids)
- tmp_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, source=txt_msg) or txt_msg
- translated_msg = tmp_msg % params
+ tmp_msg = msg(self, cr, uid, ids, context=context)
+ # Why translate something that has been generated dynamically?
+ # tmp_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, source=txt_msg) or txt_msg
+ if isinstance(tmp_msg, tuple):
+ tmp_msg, params = tmp_msg
+ translated_msg = tmp_msg % params
+ else:
+ translated_msg = tmp_msg
else:
translated_msg = trans._get_source(cr, uid, self._name, 'constraint', lng, source=msg) or msg
error_msgs.append(
:param fields_list: list of fields to get the default values for (example ['field1', 'field2',])
:type fields_list: list
- :param context: usual context dictionary - it may contains keys in the form ``default_XXX``,
- where XXX is a field name to set or override a default value.
+ :param context: optional context dictionary - it may contains keys for specifying certain options
+ like ``context_lang`` (language) or ``context_tz`` (timezone) to alter the results of the call.
+ It may contain keys in the form ``default_XXX`` (where XXX is a field name), to set
+ or override a default value for a field.
+ A special ``bin_size`` boolean flag may also be passed in the context to request the
+ value of all fields.binary columns to be returned as the size of the binary instead of its
+ contents. This can also be selectively overriden by passing a field-specific flag
+ in the form ``bin_size_XXX: True/False`` where ``XXX`` is the name of the field.
+ Note: The ``bin_size_XXX`` form is new in OpenERP v6.0.
:return: dictionary of the default values (set on the object model class, through user preferences, or in the context)
"""
# trigger view init hook
context = {}
result = False
fields = {}
- childs = True
+ children = True
def encode(s):
if isinstance(s, unicode):
if column:
relation = self.pool.get(column._obj)
- childs = False
+ children = False
views = {}
for f in node:
if f.tag in ('form', 'tree', 'graph'):
node.set('sum', trans)
for f in node:
- if childs or (node.tag == 'field' and f.tag in ('filter','separator')):
+ if children or (node.tag == 'field' and f.tag in ('filter','separator')):
fields.update(self.__view_look_dom(cr, user, f, view_id, context))
return fields
fields = self.fields_get(cr, user, fields_def.keys(), context)
for field in fields_def:
if field == 'id':
- # sometime, the view may containt the (invisible) field 'id' needed for a domain (when 2 objects have cross references)
+ # sometime, the view may contain the (invisible) field 'id' needed for a domain (when 2 objects have cross references)
fields['id'] = {'readonly': True, 'type': 'integer', 'string': 'ID'}
elif field in fields:
fields[field].update(fields_def[field])
model = res[0][1]
res.insert(0, ("Can't find field '%s' in the following view parts composing the view of object model '%s':" % (field, model), None))
msg = "\n * ".join([r[0] for r in res])
- msg += "\n\nEither you wrongly customised this view, or some modules bringing those views are not compatible with your current data model"
+ msg += "\n\nEither you wrongly customized this view, or some modules bringing those views are not compatible with your current data model"
netsvc.Logger().notifyChannel('orm', netsvc.LOG_ERROR, msg)
raise except_orm('View error', msg)
return arch, fields
return arch
- def __get_default_search_view(self, cr, uid, context={}):
+ def __get_default_search_view(self, cr, uid, context=None):
def encode(s):
if isinstance(s, unicode):
return s.encode('utf8')
return s
- view = self.fields_view_get(cr, uid, False, 'form', context)
+ view = self.fields_view_get(cr, uid, False, 'form', context=context)
root = etree.fromstring(encode(view['arch']))
res = etree.XML("""<search string="%s"></search>""" % root.get("string", ""))
where += ' order by '+self._parent_order
cr.execute('SELECT id FROM '+self._table+' WHERE '+where)
pos2 = pos + 1
- childs = cr.fetchall()
- for id in childs:
+ for id in cr.fetchall():
pos2 = browse_rec(id[0], pos2)
cr.execute('update '+self._table+' set parent_left=%s, parent_right=%s where id=%s', (pos, pos2, root))
return pos2 + 1
self.__schema.debug("Table '%s': column '%s': dropped NOT NULL constraint",
self._table, column['attname'])
- def _auto_init(self, cr, context={}):
+ def _auto_init(self, cr, context=None):
+ if context is None:
+ context = {}
store_compute = False
create = False
todo_end = []
cr.execute('CREATE TABLE "%s" (id SERIAL NOT NULL, PRIMARY KEY(id)) WITHOUT OIDS' % (self._table,))
cr.execute("COMMENT ON TABLE \"%s\" IS '%s'" % (self._table, self._description.replace("'", "''")))
create = True
-
self.__schema.debug("Table '%s': created", self._table)
cr.commit()
# iterate on the "object columns"
todo_update_store = []
update_custom_fields = context.get('update_custom_fields', False)
+
+ cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \
+ "FROM pg_class c,pg_attribute a,pg_type t " \
+ "WHERE c.relname=%s " \
+ "AND c.oid=a.attrelid " \
+ "AND a.atttypid=t.oid", (self._table,))
+ col_data = dict(map(lambda x: (x['attname'], x),cr.dictfetchall()))
+
+
for k in self._columns:
if k in ('id', 'write_uid', 'write_date', 'create_uid', 'create_date'):
continue
- #raise _('Can not define a column %s. Reserved keyword !') % (k,)
#Not Updating Custom fields
if k.startswith('x_') and not update_custom_fields:
continue
+
f = self._columns[k]
if isinstance(f, fields.one2many):
self.__schema.debug("Create table '%s': relation between '%s' and '%s'",
f._rel, self._table, ref)
else:
- cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \
- "FROM pg_class c,pg_attribute a,pg_type t " \
- "WHERE c.relname=%s " \
- "AND a.attname=%s " \
- "AND c.oid=a.attrelid " \
- "AND a.atttypid=t.oid", (self._table, k))
- res = cr.dictfetchall()
+ res = col_data.get(k, [])
+ res = res and [res] or []
if not res and hasattr(f, 'oldname'):
cr.execute("SELECT c.relname,a.attname,a.attlen,a.atttypmod,a.attnotnull,a.atthasdef,t.typname,CASE WHEN a.attlen=-1 THEN a.atttypmod-4 ELSE a.attlen END as size " \
"FROM pg_class c,pg_attribute a,pg_type t " \
return super(orm, self).fields_get(cr, user, fields, context, write_access)
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
- """
- Read records with given ids with the given fields
-
- :param cr: database cursor
- :param user: current user id
- :param ids: id or list of the ids of the records to read
- :param fields: optional list of field names to return (default: all fields would be returned)
- :type fields: list (example ['field_name_1', ...])
- :param context: (optional) context arguments, like lang, time zone
- :return: list of dictionaries((dictionary per record asked)) with requested field values
- :rtype: [{‘name_of_the_field’: value, ...}, ...]
- :raise AccessError: * if user has no read rights on the requested object
- * if user tries to bypass access rules for read on the requested object
-
- """
if not context:
context = {}
self.pool.get('ir.model.access').check(cr, user, self._name, 'read', context=context)
cr.execute(query, [tuple(sub_ids)] + rule_params)
if cr.rowcount != len(sub_ids):
raise except_orm(_('AccessError'),
- _('You try to bypass an access rule while reading (Document type: %s).') % self._description)
+ _('Operation prohibited by access rules, or performed on an already deleted document (Operation: read, Document type: %s).')
+ % (self._description,))
else:
cr.execute(query, (tuple(sub_ids),))
res.extend(cr.dictfetchall())
else:
default['state'] = self._defaults['state']
- context_wo_lang = context
+ context_wo_lang = context.copy()
if 'lang' in context:
del context_wo_lang['lang']
- data = self.read(cr, uid, [id], context=context_wo_lang)[0]
+ data = self.read(cr, uid, [id,], context=context_wo_lang)
+ if data:
+ data = data[0]
+ else:
+ raise IndexError( _("Record #%d of %s not found, cannot copy!") %( id, self._name))
fields = self.fields_get(cr, uid, context=context)
for f in fields:
old_record, new_record = self.read(cr, uid, [old_id, new_id], [field_name], context=context)
# here we rely on the order of the ids to match the translations
# as foreseen in copy_data()
- old_childs = sorted(old_record[field_name])
- new_childs = sorted(new_record[field_name])
- for (old_child, new_child) in zip(old_childs, new_childs):
+ old_children = sorted(old_record[field_name])
+ new_children = sorted(new_record[field_name])
+ for (old_child, new_child) in zip(old_children, new_children):
# recursive copy of translations here
target_obj.copy_translations(cr, uid, old_child, new_child, context=context)
# and for translatable fields we keep them for copy
return cr.fetchone()[0] == len(ids)
def check_recursion(self, cr, uid, ids, parent=None):
+ warnings.warn("You are using deprecated %s.check_recursion(). Please use the '_check_recursion()' instead!" % \
+ self._name, DeprecationWarning, stacklevel=3)
+ assert ' ' not in (parent or '')
+ return self._check_recursion(cr, uid, ids, parent)
+
+ def _check_recursion(self, cr, uid, ids, parent=None):
"""
Verifies that there is no loop in a hierarchical structure of records,
by following the parent relationship using the **parent** field until a loop