summaryrefslogtreecommitdiff
path: root/bin/osv
diff options
context:
space:
mode:
authorJay (Open ERP) <jvo@tinyerp.com>2010-05-20 12:00:44 +0530
committerJay (Open ERP) <jvo@tinyerp.com>2010-05-20 12:00:44 +0530
commite3ccef27d33ff83ddbb7bfd3eacc80f8a98bd21d (patch)
treef14fb77ab9702c91bcb9309724e5aa63a96ee570 /bin/osv
parent2669744f4f09ca6ac9219dc91909e895559c74c0 (diff)
parentfe7673b7ba1f2706b8ed2abe6892ad33211063cd (diff)
[BACKPORT] Stable fixes and refactorings to Trunk
bzr revid: jvo@tinyerp.com-20100520063044-sviy1e9pybirhpsw
Diffstat (limited to 'bin/osv')
-rw-r--r--bin/osv/expression.py7
-rw-r--r--bin/osv/fields.py4
-rw-r--r--bin/osv/orm.py154
-rw-r--r--bin/osv/osv.py3
4 files changed, 109 insertions, 59 deletions
diff --git a/bin/osv/expression.py b/bin/osv/expression.py
index 4e6e1aade6f..2ca19bbf418 100644
--- a/bin/osv/expression.py
+++ b/bin/osv/expression.py
@@ -280,8 +280,11 @@ class expression(object):
c = context.copy()
c['active_test'] = False
res_ids = field_obj.name_search(cr, uid, right, [], operator, limit=None, context=c)
- right = map(lambda x: x[0], res_ids)
- self.__exp[i] = (left, 'in', right)
+ if not res_ids:
+ self.__exp[i] = ('id','=',0)
+ else:
+ right = map(lambda x: x[0], res_ids)
+ self.__exp[i] = (left, 'in', right)
else:
# other field type
# add the time part to datetime field when it's not there:
diff --git a/bin/osv/fields.py b/bin/osv/fields.py
index a38301ba184..dbddbb913e9 100644
--- a/bin/osv/fields.py
+++ b/bin/osv/fields.py
@@ -39,7 +39,7 @@ from psycopg2 import Binary
import warnings
import tools
-
+from tools.translate import _
def _symbol_set(symb):
if symb == None or symb == False:
@@ -748,7 +748,7 @@ class related(function):
ids=[ids]
objlst = obj.browse(cr, uid, ids)
for data in objlst:
- t_id=None
+ t_id = None
t_data = data
relation = obj._name
for i in range(len(self.arg)):
diff --git a/bin/osv/orm.py b/bin/osv/orm.py
index d9fce0c765b..e3514df8ae0 100644
--- a/bin/osv/orm.py
+++ b/bin/osv/orm.py
@@ -49,6 +49,7 @@ import string
import sys
import time
import traceback
+import datetime
import types
import fields
@@ -58,6 +59,7 @@ from tools.translate import _
import copy
import sys
+import operator
try:
from lxml import etree
@@ -86,7 +88,6 @@ def last_day_of_current_month():
def intersect(la, lb):
return filter(lambda x: x in lb, la)
-
class except_orm(Exception):
def __init__(self, name, value):
self.name = name
@@ -276,7 +277,7 @@ class browse_record(object):
else:
new_data[n] = data[n]
self._data[data['id']].update(new_data)
-
+
if not name in self._data[self._id]:
#how did this happen?
self.logger.notifyChannel("browse_record", netsvc.LOG_ERROR,
@@ -447,7 +448,7 @@ class orm_template(object):
'name': k,
'field_description': f.string.replace("'", " "),
'ttype': f._type,
- 'relation': f._obj or 'NULL',
+ 'relation': f._obj or '',
'view_load': (f.view_load and 1) or 0,
'select_level': tools.ustr(f.select or 0),
'readonly':(f.readonly and 1) or 0,
@@ -544,6 +545,8 @@ class orm_template(object):
return browse_null()
def __export_row(self, cr, uid, row, fields, context=None):
+ if context is None:
+ context = {}
def check_type(field_type):
if field_type == 'float':
@@ -597,9 +600,9 @@ class orm_template(object):
cols = selection_field(self._inherits)
if cols and cols._type == 'selection':
sel_list = cols.selection
- if type(sel_list) == type([]):
- r = [x[1] for x in sel_list if r==x[0]][0]
-
+ if r and type(sel_list) == type([]):
+ r = [x[1] for x in sel_list if r==x[0]]
+ r = r and r[0] or False
if not r:
if f[i] in self._columns:
r = check_type(self._columns[f[i]]._type)
@@ -626,7 +629,7 @@ class orm_template(object):
for rr in r :
if isinstance(rr.name, browse_record):
rr = rr.name
- rr_name = self.pool.get(rr._table_name).name_get(cr, uid, [rr.id])
+ rr_name = self.pool.get(rr._table_name).name_get(cr, uid, [rr.id], context=context)
rr_name = rr_name and rr_name[0] and rr_name[0][1] or ''
dt += tools.ustr(rr_name or '') + ','
data[fpos] = dt[:-1]
@@ -639,7 +642,7 @@ class orm_template(object):
i += 1
if i == len(f):
if isinstance(r, browse_record):
- r = self.pool.get(r._table_name).name_get(cr, uid, [r.id])
+ r = self.pool.get(r._table_name).name_get(cr, uid, [r.id], context=context)
r = r and r[0] and r[0][1] or ''
data[fpos] = tools.ustr(r or '')
return [data] + lines
@@ -795,12 +798,12 @@ class orm_template(object):
module, xml_id = line[i].rsplit('.', 1)
else:
module, xml_id = current_module, line[i]
- id = ir_model_data_obj._get_id(cr, uid, module, xml_id)
-
- res_res_id = ir_model_data_obj.read(cr, uid, [id],
- ['res_id'])
- if res_res_id:
- res_id = res_res_id[0]['res_id']
+ record_id = ir_model_data_obj._get_id(cr, uid, module, xml_id)
+ ir_model_data = ir_model_data_obj.read(cr, uid, [record_id], ['res_id'])
+ if ir_model_data:
+ res_id = ir_model_data[0]['res_id']
+ else:
+ raise ValueError('No references to %s.%s' % (module, xml_id))
row[field[-1][:-3]] = res_id or False
continue
if (len(field) == len(prefix)+1) and \
@@ -994,7 +997,8 @@ class orm_template(object):
msg = _('Insertion Failed! ' + e[1])
return (-1, res, 'Line ' + str(counter) +' : ' + msg, '' )
#Raising Uncaught exception
- raise
+ return (-1, res, 'Line ' + str(counter) +' : ' + str(e), '' )
+
for lang in translate:
context2 = context.copy()
context2['lang'] = lang
@@ -1003,6 +1007,8 @@ class orm_template(object):
data = pickle.load(file(config.get('import_partial')))
data[filename] = initial_size - len(datas) + original_value
pickle.dump(data, file(config.get('import_partial'),'wb'))
+ if context.get('defer_parent_store_computation'):
+ self._parent_store_compute(cr)
cr.commit()
#except Exception, e:
@@ -1016,6 +1022,8 @@ class orm_template(object):
#
# TODO: Send a request with the result and multi-thread !
#
+ if context.get('defer_parent_store_computation'):
+ self._parent_store_compute(cr)
return (done, 0, 0, 0)
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
@@ -1108,8 +1116,7 @@ class orm_template(object):
if getattr(self._columns[f], arg, None):
res[f][arg] = getattr(self._columns[f], arg)
- #TODO: optimize
- res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context.get('lang', False) or 'en_US')
+ res_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'field', context.get('lang', False) or 'en_US', self._columns[f].string)
if res_trans:
res[f]['string'] = res_trans
help_trans = translation_obj._get_source(cr, user, self._name + ',' + f, 'help', context.get('lang', False) or 'en_US')
@@ -1724,7 +1731,8 @@ class orm_template(object):
for lang in langs:
for field in vals:
if field in self._columns:
- self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field])
+ src = self._columns[field].string
+ self.pool.get('ir.translation')._set_ids(cr, uid, self._name+','+field, 'field', lang, [0], vals[field], src)
for table in self._inherits:
cols = intersect(self._inherit_fields.keys(), vals)
if cols:
@@ -2137,6 +2145,8 @@ class orm(orm_template):
return (tables, where_clause)
def _parent_store_compute(self, cr):
+ if not self._parent_store:
+ return
logger = netsvc.Logger()
logger.notifyChannel('orm', netsvc.LOG_INFO, 'Computing parent left and right for table %s...' % (self._table, ))
def browse_rec(root, pos=0):
@@ -2225,8 +2235,8 @@ class orm(orm_template):
logger.notifyChannel('orm', netsvc.LOG_ERROR, 'create a column parent_left on object %s: fields.integer(\'Left Parent\', select=1)' % (self._table, ))
if 'parent_right' not in self._columns:
logger.notifyChannel('orm', netsvc.LOG_ERROR, 'create a column parent_right on object %s: fields.integer(\'Right Parent\', select=1)' % (self._table, ))
- if self._columns[self._parent_name].ondelete<>'cascade':
- logger.notifyChannel('orm', netsvc.LOG_ERROR, "the columns %s on object must be set as ondelete='cascasde'" % (self._name, self._parent_name))
+ if self._columns[self._parent_name].ondelete != 'cascade':
+ logger.notifyChannel('orm', netsvc.LOG_ERROR, "The column %s on object %s must be set as ondelete='cascade'" % (self._parent_name, self._name))
cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_left" INTEGER' % (self._table,))
cr.execute('ALTER TABLE "%s" ADD COLUMN "parent_right" INTEGER' % (self._table,))
cr.commit()
@@ -2472,6 +2482,8 @@ class orm(orm_template):
cr.execute("SELECT relname FROM pg_class WHERE relkind in ('r','v') AND relname=%s", (self._table,))
create = not bool(cr.fetchone())
+ cr.commit() # start a new transaction
+
for (key, con, _) in self._sql_constraints:
conname = '%s_%s' % (self._table, key)
cr.execute("SELECT conname FROM pg_constraint where conname=%s", (conname,))
@@ -2481,6 +2493,7 @@ class orm(orm_template):
cr.commit()
except:
logger.notifyChannel('orm', netsvc.LOG_WARNING, 'unable to add \'%s\' constraint on table %s !\n If you want to have it, you should update the records and execute manually:\nALTER table %s ADD CONSTRAINT %s_%s %s' % (con, self._table, self._table, self._table, key, con,))
+ cr.rollback()
if create:
if hasattr(self, "_sql"):
@@ -2491,6 +2504,7 @@ class orm(orm_template):
cr.commit()
if store_compute:
self._parent_store_compute(cr)
+ cr.commit()
return todo_end
def __init__(self, cr):
@@ -2646,11 +2660,16 @@ class orm(orm_template):
for i in range(len(field_value)):
field_value2.append({})
for field2 in field_value[i]:
- if obj._columns[field2]._type in ('many2one', 'one2one'):
+ if field2 in obj._columns.keys() and obj._columns[field2]._type in ('many2one', 'one2one'):
obj2 = self.pool.get(obj._columns[field2]._obj)
if not obj2.search(cr, uid,
[('id', '=', field_value[i][field2])]):
continue
+ elif field2 in obj._inherit_fields.keys() and obj._inherit_fields[field2][2]._type in ('many2one', 'one2one'):
+ obj2 = self.pool.get(obj._inherit_fields[field2][2]._obj)
+ if not obj2.search(cr, uid,
+ [('id', '=', field_value[i][field2])]):
+ continue
# TODO add test for many2many and one2many
field_value2[i][field2] = field_value[i][field2]
field_value = field_value2
@@ -3107,6 +3126,24 @@ class orm(orm_template):
self.pool.get('ir.model.access').check(cr, user, self._name, 'write', context=context)
+ # No direct update of parent_left/right
+ vals.pop('parent_left', None)
+ vals.pop('parent_right', None)
+
+ parents_changed = []
+ if self._parent_store and (self._parent_name in vals):
+ # The parent_left/right computation may take up to
+ # 5 seconds. No need to recompute the values if the
+ # parent is the same. Get the current value of the parent
+ base_query = 'SELECT id FROM %s WHERE id IN %%s AND %s' % \
+ (self._table, self._parent_name)
+ params = (tuple(ids),)
+ parent_val = vals[self._parent_name]
+ if parent_val:
+ cr.execute(base_query + " != %s", params + (parent_val,))
+ else:
+ cr.execute(base_query + " IS NULL", params)
+ parents_changed = map(operator.itemgetter(0), cr.fetchall())
upd0 = []
upd1 = []
@@ -3196,41 +3233,48 @@ class orm(orm_template):
self.pool.get(table).write(cr, user, nids, v, context)
self._validate(cr, user, ids, context)
-# TODO: use _order to set dest at the right position and not first node of parent
- if self._parent_store and (self._parent_name in vals):
+
+ # TODO: use _order to set dest at the right position and not first node of parent
+ # We can't defer parent_store computation because the stored function
+ # fields that are computer may refer (directly or indirectly) to
+ # parent_left/right (via a child_of domain)
+ if parents_changed:
if self.pool._init:
self.pool._init_parent[self._name]=True
else:
- for id in ids:
+ order = self._parent_order or self._order
+ parent_val = vals[self._parent_name]
+ if parent_val:
+ clause, params = '%s=%%s' % (self._parent_name,), (parent_val,)
+ else:
+ clause, params = '%s IS NULL' % (self._parent_name,), ()
+ cr.execute('SELECT parent_right, id FROM %s WHERE %s ORDER BY %s' % (self._table, clause, order), params)
+ parents = cr.fetchall()
+
+ for id in parents_changed:
+ cr.execute('SELECT parent_left, parent_right FROM %s WHERE id=%%s' % (self._table,), (id,))
+ pleft, pright = cr.fetchone()
+ distance = pright - pleft + 1
+
# Find Position of the element
- if vals[self._parent_name]:
- cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+'=%s order by '+(self._parent_order or self._order), (vals[self._parent_name],))
- else:
- cr.execute('select parent_left,parent_right,id from '+self._table+' where '+self._parent_name+' is null order by '+(self._parent_order or self._order))
- result_p = cr.fetchall()
position = None
- for (pleft,pright,pid) in result_p:
- if pid == id:
+ for (parent_pright, parent_id) in parents:
+ if parent_id == id:
break
- position = pright+1
+ position = parent_pright+1
- # It's the first node of the parent: position = parent_left+1
+ # It's the first node of the parent
if not position:
- if not vals[self._parent_name]:
+ if not parent_val:
position = 1
else:
- cr.execute('select parent_left from '+self._table+' where id=%s', (vals[self._parent_name],))
+ cr.execute('select parent_left from '+self._table+' where id=%s', (parent_val,))
position = cr.fetchone()[0]+1
- # We have the new position !
- cr.execute('select parent_left,parent_right from '+self._table+' where id=%s', (id,))
- pleft,pright = cr.fetchone()
- distance = pright - pleft + 1
-
- if position>pleft and position<=pright:
+ if pleft < position <= pright:
raise except_orm(_('UserError'), _('Recursivity Detected.'))
- if pleft<position:
+ if pleft < position:
cr.execute('update '+self._table+' set parent_left=parent_left+%s where parent_left>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_right=parent_right+%s where parent_right>=%s', (distance, position))
cr.execute('update '+self._table+' set parent_left=parent_left+%s, parent_right=parent_right+%s where parent_left>=%s and parent_left<%s', (position-pleft,position-pleft, pleft, pright))
@@ -3411,7 +3455,7 @@ class orm(orm_template):
self.check_access_rule(cr, user, [id_new], 'create', context=context)
upd_todo.sort(lambda x, y: self._columns[x].priority-self._columns[y].priority)
- if self._parent_store:
+ if self._parent_store and not context.get('defer_parent_store_computation'):
if self.pool._init:
self.pool._init_parent[self._name]=True
else:
@@ -3639,8 +3683,9 @@ class orm(orm_template):
* '&' (default), '|', '!'
"""
- if not context:
+ if context is None:
context = {}
+ self.pool.get('ir.model.access').check(cr, user, self._name, 'read', context=context)
# compute the where, order by, limit and offset clauses
(qu1, qu2, tables) = self._where_calc(cr, user, args, context=context)
dom = self.pool.get('ir.rule').domain_get(cr, user, self._name, 'read', context=context)
@@ -3750,9 +3795,9 @@ class orm(orm_template):
:return: dictionary containing all the field values
"""
- if not context:
+ if context is None:
context = {}
- if not default:
+ if default is None:
default = {}
if 'state' not in default:
if 'state' in self._defaults:
@@ -3761,7 +3806,11 @@ class orm(orm_template):
else:
default['state'] = self._defaults['state']
- data = self.read(cr, uid, [id], context=context)[0]
+ context_wo_lang = context
+ if 'lang' in context:
+ del context_wo_lang['lang']
+ data = self.read(cr, uid, [id], context=context_wo_lang)[0]
+
fields = self.fields_get(cr, uid, context=context)
trans_data=[]
for f in fields:
@@ -3796,17 +3845,14 @@ class orm(orm_template):
trans_obj = self.pool.get('ir.translation')
#TODO: optimize translations
- trans_name=''
for f in fields:
- trans_flag=True
+ trans_name = ''
if f in self._columns and self._columns[f].translate:
- trans_name=self._name+","+f
+ trans_name = self._name+","+f
elif f in self._inherit_fields and self._inherit_fields[f][2].translate:
- trans_name=self._inherit_fields[f][0]+","+f
- else:
- trans_flag=False
+ trans_name = self._inherit_fields[f][0] + "," + f
- if trans_flag:
+ if trans_name:
trans_ids = trans_obj.search(cr, uid, [
('name', '=', trans_name),
('res_id','=',data['id'])
diff --git a/bin/osv/osv.py b/bin/osv/osv.py
index a528d418089..08f62e50230 100644
--- a/bin/osv/osv.py
+++ b/bin/osv/osv.py
@@ -253,7 +253,8 @@ class osv(osv_base, orm.orm):
for c in cls.__dict__.get(s, []):
exist = False
for c2 in range(len(new)):
- if new[c2][2]==c[2]:
+ #For _constraints, we should check field and methods as well
+ if new[c2][2]==c[2] and new[c2][0]==c[0]:
new[c2] = c
exist = True
break