Merge remote branch 'origin/master' into optimize

Conflicts:
	bin/osv/expression.py
	bin/osv/orm.py

bzr revid: p_christ@hol.gr-20091026105650-49wvuk3o7qw1ybkn
This commit is contained in:
P. Christeas
2009-10-26 12:56:50 +02:00
6 changed files with 153 additions and 43 deletions
+2 -1
View File
@@ -415,7 +415,8 @@ class ir_model_data(osv.osv):
_defaults = {
'date_init': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'date_update': lambda *a: time.strftime('%Y-%m-%d %H:%M:%S'),
'noupdate': lambda *a: False
'noupdate': lambda *a: False,
'module': lambda *a: ''
}
_sql_constraints = [
('module_name_uniq', 'unique(name, module)', 'You can not have multiple records with the same id for the same module'),
@@ -25,7 +25,7 @@ from report import report_sxw
class ir_module_reference_print(report_sxw.rml_parse):
def __init__(self, cr, uid, name, context):
super(ir_module_reference_print, self).__init__(cr, uid, name, context)
super(ir_module_reference_print, self).__init__(cr, uid, name, context=context)
self.localcontext.update({
'time': time,
'findobj': self._object_find,
+69 -21
View File
@@ -44,18 +44,28 @@ class expression(object):
and (((not internal) and element[1] in OPS) \
or (internal and element[1] in INTERNAL_OPS))
def __execute_recursive_in(self, cr, s, f, w, ids):
def __execute_recursive_in(self, cr, s, f, w, ids, op, type):
# todo: merge into parent query as sub-query
res = []
for i in range(0, len(ids), cr.IN_MAX):
subids = ids[i:i+cr.IN_MAX]
cr.execute('SELECT "%s"' \
' FROM "%s"' \
if ids:
if op in ['<','>','>=','<=']:
cr.execute('SELECT "%s"' \
' FROM "%s"' \
' WHERE "%s" %s %s' % (s, f, w, op, ids[0]))
res.extend([r[0] for r in cr.fetchall()])
else:
for i in range(0, len(ids), cr.IN_MAX):
subids = ids[i:i+cr.IN_MAX]
cr.execute('SELECT "%s"' \
' FROM "%s"' \
' WHERE "%s" = ANY (%%s)' % (s, f, w), (subids,))
res.extend([r[0] for r in cr.fetchall()])
else:
cr.execute('SELECT distinct("%s")' \
' FROM "%s" where "%s" is not null' % (s, f, s)),
res.extend([r[0] for r in cr.fetchall()])
return res
def __init__(self, exp):
# check if the expression is valid
if not reduce(lambda acc, val: acc and (self._is_operator(val) or self._is_leaf(val)), exp, True):
@@ -101,7 +111,6 @@ class expression(object):
if self._is_operator(e) or e == self.__DUMMY_LEAF:
continue
left, operator, right = e
working_table = table
main_table = table
fargs = left.split('.', 1)
@@ -154,14 +163,32 @@ class expression(object):
elif field._type == 'one2many':
if isinstance(right, basestring):
ids2 = [x[0] for x in field_obj.name_search(cr, uid, right, [], operator, limit=None)]
else:
ids2 = list(right)
if not ids2:
self.__exp[i] = ('id', '=', '0')
else:
self.__exp[i] = ('id', 'in', self.__execute_recursive_in(cr, field._fields_id, field_obj._table, 'id', ids2))
call_null = True
if right:
if isinstance(right, basestring):
ids2 = [x[0] for x in field_obj.name_search(cr, uid, right, [], operator, limit=None)]
operator = 'in'
else:
if not isinstance(right,list):
ids2 = [right]
else:
ids2 = right
if not ids2:
call_null = True
operator = 'in' # operator changed because ids are directly related to main object
else:
call_null = False
o2m_op = 'in'
if operator in ['not like','not ilike','not in','<>','!=']:
o2m_op = 'not in'
self.__exp[i] = ('id', o2m_op, self.__execute_recursive_in(cr, field._fields_id, field_obj._table, 'id', ids2, operator, field._type))
if call_null:
o2m_op = 'not in'
if operator in ['not like','not ilike','not in','<>','!=']:
o2m_op = 'in'
self.__exp[i] = ('id', o2m_op, self.__execute_recursive_in(cr, field._fields_id, field_obj._table, 'id', [], operator, field._type) or [0])
elif field._type == 'many2many':
#FIXME
@@ -174,17 +201,38 @@ class expression(object):
def _rec_convert(ids):
if field_obj == table:
return ids
return self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, ids)
return self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, ids, operator, field._type)
dom = _rec_get(ids2, field_obj)
ids2 = field_obj.search(cr, uid, dom, context=context)
self.__exp[i] = ('id', 'in', _rec_convert(ids2))
else:
if isinstance(right, basestring):
res_ids = [x[0] for x in field_obj.name_search(cr, uid, right, [], operator)]
else:
res_ids = list(right)
self.__exp[i] = ('id', 'in', self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, res_ids) or [0])
call_null_m2m = True
if right:
if isinstance(right, basestring):
res_ids = [x[0] for x in field_obj.name_search(cr, uid, right, [], operator)]
operator = 'in'
else:
if not isinstance(right, list):
res_ids = [right]
else:
res_ids = right
if not res_ids:
call_null_m2m = True
operator = 'in' # operator changed because ids are directly related to main object
else:
call_null_m2m = False
m2m_op = 'in'
if operator in ['not like','not ilike','not in','<>','!=']:
m2m_op = 'not in'
self.__exp[i] = ('id', m2m_op, self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, res_ids, operator, field._type) or [0])
if call_null_m2m:
m2m_op = 'not in'
if operator in ['not like','not ilike','not in','<>','!=']:
m2m_op = 'in'
self.__exp[i] = ('id', m2m_op, self.__execute_recursive_in(cr, field._id1, field._rel, field._id2, [], operator, field._type) or [0])
elif field._type == 'many2one':
if operator == 'child_of':
if isinstance(right, basestring):
+68 -13
View File
@@ -459,6 +459,15 @@ class orm_template(object):
return False
return ''
def selection_field(in_field):
col_obj = self.pool.get(in_field.keys()[0])
if f[i] in col_obj._columns.keys():
return col_obj._columns[f[i]]
elif f[i] in col_obj._inherits.keys():
selection_field(col_obj._inherits)
else:
return False
lines = []
data = map(lambda x: '', range(len(fields)))
done = []
@@ -482,7 +491,19 @@ class orm_template(object):
else:
break
else:
r = r[f[i]]
r = r[f[i]]
# To display external name of selection field when its exported
if not context.get('import_comp',False):# Allow external name only if its not import compatible
cols = False
if f[i] in self._columns.keys():
cols = self._columns[f[i]]
elif f[i] in self._inherit_fields.keys():
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 not r:
if f[i] in self._columns:
r = check_type(self._columns[f[i]]._type)
@@ -588,6 +609,9 @@ class orm_template(object):
continue
field = fields[i]
if prefix and not prefix[0] in field:
continue
if (len(field)==len(prefix)+1) and field[len(prefix)].endswith(':db_id'):
# Database ID
res = False
@@ -646,7 +670,7 @@ class orm_template(object):
['res_id'])
if res_res_id:
res_id = res_res_id[0]['res_id']
row[field[0][:-3]] = res_id or False
row[field[-1][:-3]] = res_id or False
continue
if (len(field) == len(prefix)+1) and \
len(field[len(prefix)].split(':lang=')) == 2:
@@ -682,7 +706,7 @@ class orm_template(object):
try:
_check_db_id(self, model_name, line[i])
data_res_id = is_db_id = int(line[i])
except Exception,e:
except Exception,e:
warning += [tools.exception_to_unicode(e)]
logger.notifyChannel("import", netsvc.LOG_ERROR,
tools.exception_to_unicode(e))
@@ -1071,19 +1095,37 @@ class orm_template(object):
buttons = (n for n in node.getElementsByTagName('button') if n.getAttribute('type') != 'object')
for button in buttons:
ok = True
can_click = True
if user != 1: # admin user has all roles
user_roles = usersobj.read(cr, user, [user], ['roles_id'])[0]['roles_id']
cr.execute("select role_id from wkf_transition where signal=%s", (button.getAttribute('name'),))
# TODO handle the case of more than one workflow for a model
cr.execute("""SELECT DISTINCT t.role_id
FROM wkf
INNER JOIN wkf_activity a ON a.wkf_id = wkf.id
INNER JOIN wkf_transition t ON (t.act_to = a.id)
WHERE wkf.osv = %s
AND t.signal = %s
""", (self._name, button.getAttribute('name'),))
roles = cr.fetchall()
for role in roles:
if role[0]:
ok = ok and rolesobj.check(cr, user, user_roles, role[0])
# draft -> valid = signal_next (role X)
# draft -> cancel = signal_cancel (no role)
#
# valid -> running = signal_next (role Y)
# valid -> cancel = signal_cancel (role Z)
#
# running -> done = signal_next (role Z)
# running -> cancel = signal_cancel (role Z)
if not ok:
button.setAttribute('readonly', '1')
else:
button.setAttribute('readonly', '0')
# As we don't know the object state, in this scenario,
# the button "signal_cancel" will be always shown as there is no restriction to cancel in draft
# the button "signal_next" will be show if the user has any of the roles (X Y or Z)
# The verification will be made later in workflow process...
if roles:
can_click = any((not role) or rolesobj.check(cr, user, user_roles, role) for (role,) in roles)
button.setAttribute('readonly', str(int(not can_click)))
arch = node.toxml(encoding="utf-8").replace('\t', '')
fields = self.fields_get(cr, user, fields_def.keys(), context)
@@ -1221,6 +1263,15 @@ class orm_template(object):
model = True
sql_res = False
while ok:
view_ref = context.get(view_type + '_view_ref', False)
if view_ref:
if '.' in view_ref:
module, view_ref = view_ref.split('.', 1)
cr.execute("SELECT res_id FROM ir_model_data WHERE model='ir.ui.view' AND module=%s AND name=%s", (module, view_ref))
view_ref_res = cr.fetchone()
if view_ref_res:
view_id = view_ref_res[0]
if view_id:
where = (model and (" and model='%s'" % (self._name,))) or ''
cr.execute('SELECT arch,name,field_parent,id,type,inherit_id FROM ir_ui_view WHERE id=%s'+where, (view_id,))
@@ -1462,6 +1513,8 @@ class orm_memory(orm_template):
return result
def write(self, cr, user, ids, vals, context=None):
if not ids:
return True
vals2 = {}
upd_todo = []
for field in vals:
@@ -1556,7 +1609,7 @@ class orm_memory(orm_template):
# get the default values from the context
for key in context or {}:
if key.startswith('default_'):
if key.startswith('default_') and (key[8:] in fieds_list):
value[key[8:]] = context[key]
return value
@@ -2122,10 +2175,12 @@ class orm(orm_template):
else:
select = map(int,ids)
result = self._read_flat(cr, user, select, fields, context, load)
for r in result:
for key, v in r.items():
if v == None:
r[key] = False
if isinstance(ids, (int, long)):
return result and result[0] or False
return result
+3 -3
View File
@@ -475,10 +475,10 @@ class _rml_flowable(object):
if key in ('rml_except', 'rml_loop', 'rml_tag'):
del txt_n.attrib[key]
if True or not self._textual(n).isspace():
txt_n.text = utils.xml2str(self._textual(n))
txt_n.tail = ''
if not n.tag == 'bullet':
txt_n.text = utils.xml2str(self._textual(n))
txt_n.tail = n.tail and utils._process_text(self, n.tail.replace('\n','')) or ''
rc1 += etree.tostring(txt_n)
#rc1 += utils._process_text(self, node.tail or '')
return rc1
def _table(self, node):
+10 -4
View File
@@ -43,6 +43,8 @@ from lxml import etree
import copy
import tools
import locale
import netsvc
import traceback, sys
_regex = re.compile('\[\[(.+?)\]\]')
@@ -108,9 +110,13 @@ def _process_text(self, txt):
result += self.localcontext.get('translate', lambda x:x)(sps.pop(0))
if sps:
try:
txt = eval(sps.pop(0),self.localcontext)
except:
pass
expr = sps.pop(0)
txt = eval(expr,self.localcontext)
except Exception,e:
tb_s = reduce(lambda x, y: x+y, traceback.format_exception(sys.exc_type, sys.exc_value, sys.exc_traceback))
netsvc.Logger().notifyChannel('report', netsvc.LOG_ERROR,
'report :\n%s\n%s\nexpr: %s' % (tb_s, str(e),
expr.encode('utf-8')))
if type(txt)==type('') or type(txt)==type(u''):
txt2 = str2xml(txt)
result += tools.ustr(txt2)
@@ -173,7 +179,7 @@ def attr_get(node, attrs, dict={}):
res[key] = int(node.get(key))
elif dict[key]=='unit':
res[key] = unit_get(node.get(key))
elif dict[key] == 'float' :
elif dict[key] == 'float' :
res[key] = float(node.get(key))
return res