Add model.fields
Use better naming of field attributes
This commit is contained in:
1 parent
6f9b7ac07a
commit
e28edc4d99
29 files changed
+958
-855
No files matched your search
@@ -0,0 +1,4 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from postgresql import *
|
||||
@@ -0,0 +1,4 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from fields import *
|
||||
@@ -0,0 +1,193 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
import sha
|
||||
import psycopg2
|
||||
|
||||
|
||||
class Field(object):
|
||||
symbol_c = '%s'
|
||||
|
||||
@staticmethod
|
||||
def symbol_f(value):
|
||||
if value is None or value == False:
|
||||
return None
|
||||
elif isinstance(value, str):
|
||||
return unicode(value, 'utf-8')
|
||||
elif isinstance(value, unicode):
|
||||
return value
|
||||
return unicode(value)
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return None
|
||||
|
||||
|
||||
class Boolean(Field):
|
||||
|
||||
@staticmethod
|
||||
def symbol_f(value):
|
||||
return value and 'True' or 'False'
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('bool', 'bool')
|
||||
|
||||
|
||||
class Integer(Field):
|
||||
|
||||
@staticmethod
|
||||
def symbol_f(value):
|
||||
return int(value or 0)
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('int4', 'int4')
|
||||
|
||||
|
||||
class BigInteger(Integer):
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('int8', 'int8')
|
||||
|
||||
|
||||
class Char(Field):
|
||||
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
if field.size:
|
||||
return ('varchar', 'varchar(%d)' % (field.size,))
|
||||
return ('varchar', 'varchar')
|
||||
|
||||
|
||||
class Sha(Field):
|
||||
|
||||
@staticmethod
|
||||
def symbol_f(value):
|
||||
return value and sha.new(value).hexdigest() or ''
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('varchar', 'varchar(40)')
|
||||
|
||||
|
||||
class Text(Field):
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('text', 'text')
|
||||
|
||||
|
||||
class Float(Field):
|
||||
|
||||
@staticmethod
|
||||
def symbol_f(value):
|
||||
return float(value or 0.0)
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('float8', 'float8')
|
||||
|
||||
|
||||
class Numeric(Float):
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('numeric', 'numeric')
|
||||
|
||||
|
||||
class Date(Field):
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('date', 'date')
|
||||
|
||||
|
||||
class DateTime(Field):
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('timestamp', 'timestamp(0)')
|
||||
|
||||
|
||||
class Time(Field):
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('time', 'time')
|
||||
|
||||
|
||||
class Binary(Field):
|
||||
|
||||
@staticmethod
|
||||
def symbol_f(value):
|
||||
return value and psycopg2.Binary(value) or None
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('bytea', 'bytea')
|
||||
|
||||
|
||||
class Selection(Char):
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('varchar', 'varchar')
|
||||
|
||||
|
||||
class Reference(Field):
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('varchar', 'varchar')
|
||||
|
||||
|
||||
class Many2One(Field):
|
||||
|
||||
@staticmethod
|
||||
def symbol_f(value):
|
||||
return value and int(value) or None
|
||||
|
||||
@staticmethod
|
||||
def sql_type(field):
|
||||
return ('int4', 'int4')
|
||||
|
||||
|
||||
class One2Many(Field):
|
||||
pass
|
||||
|
||||
|
||||
class Many2Many(Field):
|
||||
pass
|
||||
|
||||
|
||||
class Function(Field):
|
||||
pass
|
||||
|
||||
|
||||
class Property(Function):
|
||||
pass
|
||||
|
||||
|
||||
FIELDS = {
|
||||
'boolean': Boolean,
|
||||
'integer': Integer,
|
||||
'biginteger': BigInteger,
|
||||
'char': Char,
|
||||
'sha': Sha,
|
||||
'text': Text,
|
||||
'float': Float,
|
||||
'numeric': Numeric,
|
||||
'date': Date,
|
||||
'datetime': DateTime,
|
||||
'time': Time,
|
||||
'binary': Binary,
|
||||
'selection': Selection,
|
||||
'reference': Reference,
|
||||
'many2one': Many2One,
|
||||
'one2many': One2Many,
|
||||
'many2many': Many2Many,
|
||||
'function': Function,
|
||||
'property': Property,
|
||||
}
|
||||
+58
-63
@@ -15,7 +15,7 @@ class BrowseRecordList(list):
|
||||
res = []
|
||||
for record in self:
|
||||
res2 = {}
|
||||
for field_name, field in record._table._columns.iteritems():
|
||||
for field_name, field in record._model._columns.iteritems():
|
||||
if not isinstance(record[field_name], BrowseRecordList):
|
||||
res2[field_name] = record.get_eval(field_name)
|
||||
res.append(res2)
|
||||
@@ -48,23 +48,19 @@ class BrowseRecord(object):
|
||||
An object that represents record defined by a ORM object.
|
||||
'''
|
||||
|
||||
def __init__(self, cursor, user, object_id, table, cache, context=None):
|
||||
'''
|
||||
table : the object (inherited from orm)
|
||||
context : a dictionnary with an optionnal context
|
||||
'''
|
||||
def __init__(self, cursor, user, record_id, model, cache, context=None):
|
||||
self._cursor = cursor
|
||||
self._user = user
|
||||
self._id = object_id
|
||||
self._table = table
|
||||
self._table_name = self._table._name
|
||||
self._id = record_id
|
||||
self._model = model
|
||||
self._model_name = self._model._name
|
||||
self._context = context
|
||||
self._language_cache = {}
|
||||
|
||||
cache.setdefault(table._name, {})
|
||||
self._data = cache[table._name]
|
||||
if not object_id in self._data:
|
||||
self._data[object_id] = {'id': object_id}
|
||||
cache.setdefault(model._name, {})
|
||||
self._data = cache[model._name]
|
||||
if not record_id in self._data:
|
||||
self._data[record_id] = {'id': record_id}
|
||||
self._cache = cache
|
||||
|
||||
def __getitem__(self, name):
|
||||
@@ -76,34 +72,31 @@ class BrowseRecord(object):
|
||||
# build the list of fields we will fetch
|
||||
|
||||
# fetch the definition of the field which was asked for
|
||||
if name in self._table._columns:
|
||||
col = self._table._columns[name]
|
||||
elif name in self._table._inherit_fields:
|
||||
col = self._table._inherit_fields[name][2]
|
||||
elif hasattr(self._table, name):
|
||||
return getattr(self._table, name)
|
||||
if name in self._model._columns:
|
||||
col = self._model._columns[name]
|
||||
elif name in self._model._inherit_fields:
|
||||
col = self._model._inherit_fields[name][2]
|
||||
elif hasattr(self._model, name):
|
||||
return getattr(self._model, name)
|
||||
else:
|
||||
raise Exception('Error', 'Programming error: field "%s" ' \
|
||||
'does not exist in object "%s"!' \
|
||||
% (name, self._table._name))
|
||||
'does not exist in model "%s"!' \
|
||||
% (name, self._model._name))
|
||||
|
||||
# if the field is a classic one or a many2one,
|
||||
# we'll fetch all classic and many2one fields
|
||||
if col._classic_write:
|
||||
if not hasattr(col, 'set'):
|
||||
# gen the list of "local" (ie not inherited)
|
||||
# fields which are classic or many2one
|
||||
ffields = [x for x in self._table._columns.items() \
|
||||
if x[1]._classic_write \
|
||||
ffields = [x for x in self._model._columns.items() \
|
||||
if not hasattr(x[1], 'set') \
|
||||
and x[0] not in self._data[self._id] \
|
||||
and ((not x[1].translate \
|
||||
and x[1]._type not in ('text', 'binary')) \
|
||||
or x[0] == name)]
|
||||
# gen the list of inherited fields
|
||||
inherits = [(x[0], x[1][2]) for x in \
|
||||
self._table._inherit_fields.items()]
|
||||
self._model._inherit_fields.items()]
|
||||
# complete the field list with the inherited fields
|
||||
# which are classic or many2one
|
||||
ffields += [x for x in inherits if x[1]._classic_write \
|
||||
ffields += [x for x in inherits if not hasattr(x[1], 'set') \
|
||||
and x[0] not in self._data[self._id] \
|
||||
and ((not x[1].translate \
|
||||
and x[1]._type not in ('text', 'binary')) \
|
||||
@@ -114,15 +107,17 @@ class BrowseRecord(object):
|
||||
ids = [x for x in self._data.keys() \
|
||||
if not self._data[x].has_key(name)]
|
||||
# read the data
|
||||
datas = self._table.read(self._cursor, self._user, ids,
|
||||
datas = self._model.read(self._cursor, self._user, ids,
|
||||
[x[0] for x in ffields], context=self._context)
|
||||
|
||||
# create browse records for 'remote' objects
|
||||
# create browse records for 'remote' models
|
||||
for data in datas:
|
||||
for i, j in ffields:
|
||||
if not j._obj in self._table.pool.object_name_list():
|
||||
if not hasattr(j, 'model_name') \
|
||||
or not (j.model_name in \
|
||||
self._model.pool.object_name_list()):
|
||||
continue
|
||||
obj = self._table.pool.get(j._obj)
|
||||
model = self._model.pool.get(j.model_name)
|
||||
if j._type in ('many2one',):
|
||||
if data[i]:
|
||||
if isinstance(data[i][0], (list, tuple)):
|
||||
@@ -135,12 +130,12 @@ class BrowseRecord(object):
|
||||
data[i] = BrowseRecordNull()
|
||||
else:
|
||||
data[i] = BrowseRecord(self._cursor, self._user,
|
||||
ids2, obj, self._cache,
|
||||
ids2, model, self._cache,
|
||||
context=self._context)
|
||||
elif j._type in ('one2many', 'many2many') and len(data[i]):
|
||||
data[i] = BrowseRecordList([BrowseRecord(self._cursor,
|
||||
self._user,
|
||||
isinstance(x, (list, tuple)) and x[0] or x, obj,
|
||||
isinstance(x, (list, tuple)) and x[0] or x, model,
|
||||
self._cache, context=self._context) for x in data[i]],
|
||||
self._context)
|
||||
self._data[data['id']].update(data)
|
||||
@@ -151,9 +146,9 @@ class BrowseRecord(object):
|
||||
return self[name]
|
||||
|
||||
def __contains__(self, name):
|
||||
return (name in self._table._columns) \
|
||||
or (name in self._table._inherit_fields) \
|
||||
or hasattr(self._table, name)
|
||||
return (name in self._model._columns) \
|
||||
or (name in self._model._inherit_fields) \
|
||||
or hasattr(self._model, name)
|
||||
|
||||
def __hasattr__(self, name):
|
||||
return name in self
|
||||
@@ -162,13 +157,13 @@ class BrowseRecord(object):
|
||||
return self._id
|
||||
|
||||
def __str__(self):
|
||||
return "BrowseRecord(%s, %d)" % (self._table_name, self._id)
|
||||
return "BrowseRecord(%s, %d)" % (self._model_name, self._id)
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self._table_name, self._id) == (other._table_name, other._id)
|
||||
return (self._model_name, self._id) == (other._model_name, other._id)
|
||||
|
||||
def __ne__(self, other):
|
||||
return (self._table_name, self._id) != (other._table_name, other._id)
|
||||
return (self._model_name, self._id) != (other._model_name, other._id)
|
||||
|
||||
# we need to define __unicode__ even though we've already defined __str__
|
||||
# because we have overridden __getattr__
|
||||
@@ -176,7 +171,7 @@ class BrowseRecord(object):
|
||||
return unicode(str(self))
|
||||
|
||||
def __hash__(self):
|
||||
return hash((self._table_name, self._id))
|
||||
return hash((self._model_name, self._id))
|
||||
|
||||
def __nonzero__(self):
|
||||
return bool(self._id)
|
||||
@@ -187,18 +182,18 @@ class BrowseRecord(object):
|
||||
self._context = self._context.copy()
|
||||
prev_lang = self._context.get('language') or 'en_US'
|
||||
self._context['language'] = lang
|
||||
for table in self._cache:
|
||||
for obj_id in self._cache[table]:
|
||||
for model in self._cache:
|
||||
for record_id in self._cache[model]:
|
||||
self._language_cache.setdefault(prev_lang,
|
||||
{}).setdefault(table, {}).update(
|
||||
self._cache[table][obj_id])
|
||||
{}).setdefault(model, {}).update(
|
||||
self._cache[model][record_id])
|
||||
if lang in self._language_cache \
|
||||
and table in self._language_cache[lang] \
|
||||
and obj_id in self._language_cache[lang][table]:
|
||||
self._cache[table][obj_id] = \
|
||||
self._language_cache[lang][table][obj_id]
|
||||
and model in self._language_cache[lang] \
|
||||
and record_id in self._language_cache[lang][model]:
|
||||
self._cache[model][record_id] = \
|
||||
self._language_cache[lang][model][record_id]
|
||||
else:
|
||||
self._cache[table][obj_id] = {'id': obj_id}
|
||||
self._cache[model][record_id] = {'id': record_id}
|
||||
|
||||
def get_eval(self, name):
|
||||
res = self[name]
|
||||
@@ -213,23 +208,23 @@ class BrowseRecord(object):
|
||||
|
||||
class EvalEnvironment(dict):
|
||||
|
||||
def __init__(self, record, obj):
|
||||
def __init__(self, record, model):
|
||||
super(EvalEnvironment, self).__init__()
|
||||
self.record = record
|
||||
self.obj = obj
|
||||
self._record = record
|
||||
self._model = model
|
||||
|
||||
def __getitem__(self, item):
|
||||
if item.startswith('_parent_'):
|
||||
field = item[8:]
|
||||
if field in self.obj._columns:
|
||||
_obj = self.obj._columns[field]._obj
|
||||
if field in self._model._columns:
|
||||
model_name = self._model._columns[field].model_name
|
||||
else:
|
||||
_obj = self.obj._inherit_fields[field][2]._obj
|
||||
obj = self.obj.pool.get(_obj)
|
||||
return EvalEnvironment(self.record[field], obj)
|
||||
if item in self.obj._columns \
|
||||
or item in self.obj._inherit_fields:
|
||||
return self.record.get_eval(item)
|
||||
model_name = self._model._inherit_fields[field][2].model_name
|
||||
model = self._model.pool.get(model_name)
|
||||
return EvalEnvironment(self._record[field], model)
|
||||
if item in self._model._columns \
|
||||
or item in self._model._inherit_fields:
|
||||
return self._record.get_eval(item)
|
||||
return super(EvalEnvironment, self).__getitem__(item)
|
||||
|
||||
def __getattr__(self, item):
|
||||
@@ -243,4 +238,4 @@ class EvalEnvironment(dict):
|
||||
return super(EvalEnvironment, self).get(item)
|
||||
|
||||
def __nonzero__(self):
|
||||
return bool(self.record)
|
||||
return bool(self._record)
|
||||
@@ -0,0 +1,19 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from boolean import *
|
||||
from integer import *
|
||||
from char import *
|
||||
from sha import *
|
||||
from text import *
|
||||
from float import *
|
||||
from numeric import *
|
||||
from date import *
|
||||
from binary import *
|
||||
from selection import *
|
||||
from reference import *
|
||||
from many2one import *
|
||||
from one2many import *
|
||||
from many2many import *
|
||||
from function import *
|
||||
from property import *
|
||||
@@ -0,0 +1,18 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Binary(Field):
|
||||
_type = 'binary'
|
||||
|
||||
def get(self, cursor, user, ids, model, name, values=None, context=None):
|
||||
if values is None:
|
||||
values = {}
|
||||
res = {}
|
||||
for i in values:
|
||||
res[i['id']] = i[name] and str(i[name]) or None
|
||||
for i in ids:
|
||||
res.setdefault(i, None)
|
||||
return res
|
||||
@@ -0,0 +1,8 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Boolean(Field):
|
||||
_type = 'boolean'
|
||||
@@ -0,0 +1,12 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Char(Field):
|
||||
_type = 'char'
|
||||
|
||||
def __init__(self, string='', size=None, **args):
|
||||
super(Char, self).__init__(string=string, **args)
|
||||
self.size = size
|
||||
@@ -0,0 +1,16 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Date(Field):
|
||||
_type = 'date'
|
||||
|
||||
|
||||
class DateTime(Field):
|
||||
_type = 'datetime'
|
||||
|
||||
|
||||
class Time(Field):
|
||||
_type = 'time'
|
||||
@@ -0,0 +1,26 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
|
||||
class Field(object):
|
||||
_type = None
|
||||
|
||||
def __init__(self, string='', help='', required=False, readonly=False,
|
||||
domain=None, states=None, priority=0, change_default=False,
|
||||
translate=False, select=0, on_change=None, on_change_with=None,
|
||||
depends=None, order_field=None, context=None):
|
||||
self.string = string
|
||||
self.help = help
|
||||
self.required = required
|
||||
self.readonly = readonly
|
||||
self.domain = domain or []
|
||||
self.states = states or {}
|
||||
self.priority = priority
|
||||
self.change_default = change_default
|
||||
self.translate = translate
|
||||
self.select = select
|
||||
self.on_change = on_change
|
||||
self.on_change_with = on_change_with
|
||||
self.depends = depends or []
|
||||
self.order_field = order_field
|
||||
self.context = context or ''
|
||||
@@ -0,0 +1,12 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Float(Field):
|
||||
_type = 'float'
|
||||
|
||||
def __init__(self, string='', digits=None, **args):
|
||||
super(Float, self).__init__(string=string, **args)
|
||||
self.digits = digits
|
||||
@@ -0,0 +1,59 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
import inspect
|
||||
|
||||
|
||||
class Function(Field):
|
||||
_type = 'float'
|
||||
|
||||
def __init__(self, fnct, arg=None, fnct_inv='', fnct_inv_arg=None,
|
||||
type='float', fnct_search='', model_name=None, selection=None,
|
||||
digits=None, relation=None, add_remove=None, **args):
|
||||
super(Function, self).__init__(**args)
|
||||
self.model_name = model_name
|
||||
self.fnct = fnct
|
||||
self.arg = arg
|
||||
self.fnct_inv = fnct_inv
|
||||
self.fnct_inv_arg = fnct_inv_arg
|
||||
if not self.fnct_inv:
|
||||
self.readonly = True
|
||||
self._type = type
|
||||
self.fnct_search = fnct_search
|
||||
self.selection = selection
|
||||
self.digits = digits
|
||||
if relation:
|
||||
self.model_name = relation
|
||||
self.add_remove = add_remove
|
||||
|
||||
def search(self, cursor, user, model, name, args, context=None):
|
||||
if not self.fnct_search:
|
||||
return []
|
||||
return getattr(model, self.fnct_search)(cursor, user, name, args,
|
||||
context=context)
|
||||
|
||||
def get(self, cursor, user, ids, model, name, values=None, context=None):
|
||||
if isinstance(name, list):
|
||||
names = name
|
||||
# Test is the function works with a list of names
|
||||
if 'names' in inspect.getargspec(getattr(model, self.fnct))[0]:
|
||||
return getattr(model, self.fnct)(cursor, user, ids, names,
|
||||
self.arg, context=context)
|
||||
res = {}
|
||||
for name in names:
|
||||
res[name] = getattr(model, self.fnct)(cursor, user, ids, name,
|
||||
self.arg, context=context)
|
||||
return res
|
||||
else:
|
||||
# Test is the function works with a list of names
|
||||
if 'names' in inspect.getargspec(getattr(model, self.fnct))[0]:
|
||||
name = [name]
|
||||
return getattr(model, self.fnct)(cursor, user, ids, name, self.arg,
|
||||
context=context)
|
||||
|
||||
|
||||
def set(self, cursor, user, record_id, model, name, values, context=None):
|
||||
if self.fnct_inv:
|
||||
getattr(model, self.fnct_inv)(cursor, user, record_id, name, values,
|
||||
self.fnct_inv_arg, context=context)
|
||||
@@ -0,0 +1,12 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Integer(Field):
|
||||
_type = 'integer'
|
||||
|
||||
|
||||
class BigInteger(Field):
|
||||
_type = 'biginteger'
|
||||
@@ -0,0 +1,128 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Many2Many(Field):
|
||||
_type = 'many2many'
|
||||
|
||||
def __init__(self, model_name, relation_name, origin, target, string='',
|
||||
order=None, ondelete_origin='CASCADE', ondelete_target='RESTRICT',
|
||||
**args):
|
||||
super(Many2Many, self).__init__(string=string, **args)
|
||||
self.model_name = model_name
|
||||
self.relation_name = relation_name
|
||||
self.origin = origin
|
||||
self.target = target
|
||||
self.order = order
|
||||
self.ondelete_origin = ondelete_origin
|
||||
self.ondelete_target = ondelete_target
|
||||
|
||||
def get(self, cursor, user, ids, model, name, values=None, context=None):
|
||||
if values is None:
|
||||
values = {}
|
||||
res = {}
|
||||
if not ids:
|
||||
return res
|
||||
for i in ids:
|
||||
res[i] = []
|
||||
ids_s = ','.join([str(x) for x in ids])
|
||||
model = model.pool.get(self.model_name)
|
||||
|
||||
domain1, domain2 = model.pool.get('ir.rule').domain_get(cursor,
|
||||
user, model._name, context=context)
|
||||
if domain1:
|
||||
domain1 = ' and ' + domain1
|
||||
|
||||
#TODO fix order: can have many fields
|
||||
cursor.execute('SELECT ' + self.relation_name + '.' + self.target + ', ' + \
|
||||
self.relation_name + '.' + self.origin + ' ' \
|
||||
'FROM "' + self.relation_name + '" , "' + model._table + '" ' \
|
||||
'WHERE ' + \
|
||||
self.relation_name + '.' + self.origin + ' IN (' + ids_s + ') ' \
|
||||
'AND ' + self.relation_name + '.' + self.target + ' = ' + \
|
||||
model._table + '.id ' + domain1 + \
|
||||
' ORDER BY ' + \
|
||||
','.join([model._table + '.' + x[0] + ' ' + x[1] \
|
||||
for x in (self.order or model._order)]), domain2)
|
||||
for i in cursor.fetchall():
|
||||
res[i[1]].append(i[0])
|
||||
return res
|
||||
|
||||
def set(self, cursor, user, record_id, model, name, values, context=None):
|
||||
if not values:
|
||||
return
|
||||
model = model.pool.get(self.model_name)
|
||||
for act in values:
|
||||
if act[0] == 'create':
|
||||
idnew = model.create(cursor, user, act[1], context=context)
|
||||
cursor.execute('INSERT INTO "' + self.relation_name + '" ' \
|
||||
'(' + self.origin + ', ' + self.target + ') ' \
|
||||
'VALUES (%s, %s)', (record_id, idnew))
|
||||
elif act[0] == 'write':
|
||||
model.write(cursor, user, act[1] , act[2], context=context)
|
||||
elif act[0] == 'delete':
|
||||
model.delete(cursor, user, act[1], context=context)
|
||||
elif act[0] == 'unlink':
|
||||
if isinstance(act[1], (int, long)):
|
||||
ids = [act[1]]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
if not ids:
|
||||
continue
|
||||
cursor.execute('DELETE FROM "' + self.relation_name + '" ' \
|
||||
'WHERE "' + self.origin + '" = %s ' \
|
||||
'AND "'+ self.target + '" IN (' \
|
||||
+ ','.join(['%s' for x in ids]) + ')',
|
||||
[record_id] + ids)
|
||||
elif act[0] == 'add':
|
||||
if isinstance(act[1], (int, long)):
|
||||
ids = [act[1]]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
if not ids:
|
||||
continue
|
||||
cursor.execute('SELECT "' + self.target + '" ' \
|
||||
'FROM "' + self.relation_name + '" ' \
|
||||
'WHERE "' + self.origin + '" = %s ' \
|
||||
'AND "' + self.target + '" IN (' + \
|
||||
','.join(['%s' for x in ids]) + ')',
|
||||
[record_id] + ids)
|
||||
existing_ids = []
|
||||
for row in cursor.fetchall():
|
||||
existing_ids.append(row[0])
|
||||
new_ids = [x for x in ids if x not in existing_ids]
|
||||
for new_id in new_ids:
|
||||
cursor.execute('INSERT INTO "' + self.relation_name + '" ' \
|
||||
'("' + self.origin + '", "' + self.target + '") ' \
|
||||
'VALUES (%s, %s)', (record_id, new_id))
|
||||
elif act[0] == 'unlink_all':
|
||||
cursor.execute('UPDATE "' + self.relation_name + '" ' \
|
||||
'SET "' + self.target + '" = NULL ' \
|
||||
'WHERE "' + self.target + '" = %s', (record_id,))
|
||||
elif act[0] == 'set':
|
||||
if not act[1]:
|
||||
ids = []
|
||||
else:
|
||||
ids = list(act[1])
|
||||
domain1, domain2 = model.pool.get('ir.rule').domain_get(cursor,
|
||||
user, model._name, context=context)
|
||||
if domain1:
|
||||
domain1 = ' AND ' + domain1
|
||||
cursor.execute('DELETE FROM "' + self.relation_name + '" ' \
|
||||
'WHERE "' + self.origin + '" = %s ' \
|
||||
'AND "' + self.target + '" IN (' \
|
||||
'SELECT ' + self.relation_name + '.' + self.target + ' ' \
|
||||
'FROM "' + self.relation_name + '", "' + model._table + '" ' \
|
||||
'WHERE ' + self.relation_name + '.' + self.origin + ' = %s ' \
|
||||
'AND ' + self.relation_name + '.' + self.target + ' = ' + \
|
||||
model._table + '.id ' + domain1 + ')',
|
||||
[record_id, record_id] + domain2)
|
||||
|
||||
for new_id in ids:
|
||||
cursor.execute('INSERT INTO "' + self.relation_name + '" ' \
|
||||
'("' + self.origin + '", "' + self.target + '") ' \
|
||||
'VALUES (%s, %s)', (record_id, new_id))
|
||||
else:
|
||||
raise Exception('Bad arguments')
|
||||
@@ -0,0 +1,42 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Many2One(Field):
|
||||
_type = 'many2one'
|
||||
|
||||
def __init__(self, model_name, string='', left=None, right=None,
|
||||
ondelete='SET NULL', **args):
|
||||
super(Many2One, self).__init__(string=string, **args)
|
||||
self.model_name = model_name
|
||||
self.left = left
|
||||
self.right = right
|
||||
self.ondelete = ondelete
|
||||
|
||||
def get(self, cursor, user, ids, model, name, values=None, context=None):
|
||||
if values is None:
|
||||
values = {}
|
||||
res = {}
|
||||
for i in values:
|
||||
res[i['id']] = i[name]
|
||||
for i in ids:
|
||||
res.setdefault(i, '')
|
||||
try:
|
||||
model = model.pool.get(self.model_name)
|
||||
except KeyError:
|
||||
return res
|
||||
record_names = {}
|
||||
for record_id, name in model.name_get(cursor, user,
|
||||
[isinstance(x, (list, tuple)) and x[0] or x
|
||||
for x in res.values() if x],
|
||||
context=context):
|
||||
record_names[record_id] = name
|
||||
|
||||
for i in res.keys():
|
||||
if res[i] and res[i] in record_names:
|
||||
res[i] = (res[i], record_names[res[i]])
|
||||
else:
|
||||
res[i] = False
|
||||
return res
|
||||
@@ -0,0 +1,8 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.float import Float
|
||||
|
||||
|
||||
class Numeric(Float):
|
||||
_type = 'numeric'
|
||||
@@ -0,0 +1,92 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class One2Many(Field):
|
||||
_type = 'one2many'
|
||||
|
||||
def __init__(self, model_name, field, string='', order_field=None,
|
||||
add_remove=None, **args):
|
||||
super(One2Many, self).__init__(string=string, **args)
|
||||
self.model_name = model_name
|
||||
self.field = field
|
||||
self.add_remove = add_remove
|
||||
|
||||
def get(self, cursor, user, ids, model, name, values=None, context=None):
|
||||
res = {}
|
||||
for i in ids:
|
||||
res[i] = []
|
||||
ids2 = []
|
||||
for i in range(0, len(ids), cursor.IN_MAX):
|
||||
sub_ids = ids[i:i + cursor.IN_MAX]
|
||||
ids2 += model.pool.get(self.model_name).search(cursor, user,
|
||||
[(self.field, 'in', sub_ids)], context=context)
|
||||
for i in model.pool.get(self.model_name).read(cursor, user, ids2,
|
||||
[self.field], context=context):
|
||||
res[i[self.field][0]].append( i['id'] )
|
||||
return res
|
||||
|
||||
def set(self, cursor, user, record_id, model, name, values, context=None):
|
||||
if not values:
|
||||
return
|
||||
model = model.pool.get(self.model_name)
|
||||
for act in values:
|
||||
if act[0] == 'create':
|
||||
act[1][self.field] = record_id
|
||||
model.create(cursor, user, act[1], context=context)
|
||||
elif act[0] == 'write':
|
||||
act[2][self.field] = record_id
|
||||
model.write(cursor, user, act[1] , act[2], context=context)
|
||||
elif act[0] == 'delete':
|
||||
model.delete(cursor, user, act[1], context=context)
|
||||
elif act[0] == 'unlink':
|
||||
if isinstance(act[1], (int, long)):
|
||||
ids = [act[1]]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
if not ids:
|
||||
continue
|
||||
ids = model.search(cursor, user, [
|
||||
(self.field, '=', record_id),
|
||||
('id', 'in', ids),
|
||||
], context=context)
|
||||
model.write(cursor, user, ids, {
|
||||
self.field: False,
|
||||
}, context=context)
|
||||
elif act[0] == 'add':
|
||||
if isinstance(act[1], (int, long)):
|
||||
ids = [act[1]]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
if not ids:
|
||||
continue
|
||||
ids = model.write(cursor, user, ids, {
|
||||
self.field: record_id,
|
||||
}, context=context)
|
||||
elif act[0] == 'unlink_all':
|
||||
ids = model.search(cursor, user, [
|
||||
(self.field, '=', record_id),
|
||||
], context=context)
|
||||
model.write(cursor, user, ids, {
|
||||
self.field: False,
|
||||
}, context=context)
|
||||
elif act[0] == 'set':
|
||||
if not act[1]:
|
||||
ids = [0]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
ids2 = model.search(cursor, user, [
|
||||
(self.field, '=', record_id),
|
||||
('id', 'not in', ids),
|
||||
], context=context)
|
||||
model.write(cursor, user, ids2, {
|
||||
self.field: False,
|
||||
}, context=context)
|
||||
if act[1]:
|
||||
model.write(cursor, user, ids, {
|
||||
self.field: record_id,
|
||||
}, context=context)
|
||||
else:
|
||||
raise Exception('Bad arguments')
|
||||
@@ -0,0 +1,36 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.function import Function
|
||||
|
||||
|
||||
class Property(Function):
|
||||
|
||||
def __init__(self, **args):
|
||||
super(Property, self).__init__('', **args)
|
||||
self.readonly = False
|
||||
|
||||
def get(self, cursor, user, ids, model, name, values=None, context=None):
|
||||
property_obj = model.pool.get('ir.property')
|
||||
res = property_obj.get(cursor, user, name, model._name, ids,
|
||||
context=context)
|
||||
|
||||
if self.model_name:
|
||||
model = model.pool.get(self.model_name)
|
||||
record_names = {}
|
||||
for record_id, record_name in model.name_get(cursor, user,
|
||||
[x for x in res.values() if x], context=context):
|
||||
record_names[record_id] = record_name
|
||||
for i in ids:
|
||||
if res.get(i) and res[i] in record_names:
|
||||
res[i] = (res[i], record_names[res[i]])
|
||||
else:
|
||||
res[i] = False
|
||||
return res
|
||||
|
||||
|
||||
def set(self, cursor, user, record_id, model, name, value, context=None):
|
||||
property_obj = model.pool.get('ir.property')
|
||||
return property_obj.set(cursor, user, name, model._name, record_id,
|
||||
(value and (self.model_name or '') + ',' + str(value)) or False,
|
||||
context=context)
|
||||
@@ -0,0 +1,59 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Reference(Field):
|
||||
_type = 'reference'
|
||||
|
||||
def __init__(self, string='', selection=[], **args):
|
||||
super(Reference, self).__init__(string=string, **args)
|
||||
self.selection = selection
|
||||
|
||||
def get(self, cursor, user, ids, model, name, values=None, context=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if values is None:
|
||||
values = {}
|
||||
res = {}
|
||||
for i in values:
|
||||
res[i['id']] = i[name]
|
||||
for i in ids:
|
||||
if not (i in res):
|
||||
res[i] = False
|
||||
continue
|
||||
if not res[i]:
|
||||
continue
|
||||
ref_model, ref_id = res[i].split(',', 1)
|
||||
if not ref_model:
|
||||
continue
|
||||
ref_obj = model.pool.get(ref_model)
|
||||
if not ref_obj:
|
||||
continue
|
||||
try:
|
||||
ref_id = eval(ref_id)
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
ref_id = int(ref_id)
|
||||
except:
|
||||
continue
|
||||
ctx = context.copy()
|
||||
ctx['active_test'] = False
|
||||
if ref_id \
|
||||
and not ref_obj.search(cursor, user, [
|
||||
('id', '=', ref_id),
|
||||
], context=ctx):
|
||||
ref_id = False
|
||||
if ref_id:
|
||||
ref_name = ref_obj.name_get(cursor, user, ref_id,
|
||||
context=context)
|
||||
if ref_name:
|
||||
ref_name = ref_name[0][1]
|
||||
else:
|
||||
ref_name = ''
|
||||
else:
|
||||
ref_name = ''
|
||||
res[i] = ref_model + ',(' + str(ref_id) + ',"' + ref_name + '")'
|
||||
return res
|
||||
@@ -0,0 +1,14 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Selection(Field):
|
||||
_type = 'selection'
|
||||
|
||||
def __init__(self, selection, string='', sort=True, translate=True, **args):
|
||||
super(Selection, self).__init__(string=string, **args)
|
||||
self.selection = selection
|
||||
self.sort = sort
|
||||
self.translate_selection = translate
|
||||
@@ -0,0 +1,8 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.field import Field
|
||||
|
||||
|
||||
class Sha(Field):
|
||||
_type = 'sha'
|
||||
@@ -0,0 +1,8 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model.fields.char import Char
|
||||
|
||||
|
||||
class Text(Char):
|
||||
_type = 'text'
|
||||
+21
-16
@@ -1,7 +1,7 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.osv import fields
|
||||
from trytond.model import fields
|
||||
import copy
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class Model(object):
|
||||
for attr in dir(self):
|
||||
if attr in ('_columns', '_defaults'):
|
||||
continue
|
||||
if isinstance(getattr(self, attr), fields.Column):
|
||||
if isinstance(getattr(self, attr), fields.Field):
|
||||
res[attr] = getattr(self, attr)
|
||||
self.__columns = res
|
||||
return res
|
||||
@@ -200,10 +200,12 @@ class Model(object):
|
||||
"relation, help, module) " \
|
||||
"VALUES (%s, %s, %s, %s, %s, %s, %s)",
|
||||
(model_id, field_name, field.string, field._type,
|
||||
field._obj or '', field.help, module_name))
|
||||
hasattr(field, 'model_name') and field.model_name or '',
|
||||
field.help, module_name))
|
||||
elif fields[field_name]['field_description'] != field.string \
|
||||
or fields[field_name]['ttype'] != field._type \
|
||||
or fields[field_name]['relation'] != (field._obj or '') \
|
||||
or fields[field_name]['relation'] != \
|
||||
(hasattr(field, 'model_name') and field.model_name or '') \
|
||||
or fields[field_name]['help'] != field.help:
|
||||
cursor.execute('UPDATE ir_model_field ' \
|
||||
'SET field_description = %s, ' \
|
||||
@@ -211,7 +213,8 @@ class Model(object):
|
||||
'relation = %s, ' \
|
||||
'help = %s ' \
|
||||
'WHERE id = %s ',
|
||||
(field.string, field._type, field._obj or '',
|
||||
(field.string, field._type,
|
||||
hasattr(field, 'model_name') and field.model_name or '',
|
||||
field.help, fields[field_name]['id']))
|
||||
trans_name = self._name + ',' + field_name
|
||||
if trans_name not in trans_fields:
|
||||
@@ -426,7 +429,7 @@ class Model(object):
|
||||
self._name)
|
||||
if self._columns[field]._type in ('many2one',) \
|
||||
and value[field]:
|
||||
obj = self.pool.get(self._columns[field]._obj)
|
||||
obj = self.pool.get(self._columns[field].model_name)
|
||||
if isinstance(value[field], (int, long)) \
|
||||
and hasattr(obj, 'name_get'):
|
||||
value[field] = obj.name_get(cursor, user,
|
||||
@@ -442,7 +445,7 @@ class Model(object):
|
||||
fld_def = (field in self._columns) and self._columns[field] \
|
||||
or self._inherit_fields[field][2]
|
||||
if fld_def._type in ('many2one',):
|
||||
obj = self.pool.get(fld_def._obj)
|
||||
obj = self.pool.get(fld_def.model_name)
|
||||
if not hasattr(obj, 'search') \
|
||||
or not obj.search(cursor, user, [
|
||||
('id', '=', field_value),
|
||||
@@ -453,7 +456,7 @@ class Model(object):
|
||||
field_value = obj.name_get(cursor, user, field_value,
|
||||
context=context)[0]
|
||||
if fld_def._type in ('many2many'):
|
||||
obj = self.pool.get(fld_def._obj)
|
||||
obj = self.pool.get(fld_def.model_name)
|
||||
field_value2 = []
|
||||
for i in range(len(field_value)):
|
||||
if not hasattr(obj, 'search') \
|
||||
@@ -464,14 +467,15 @@ class Model(object):
|
||||
field_value2.append(field_value[i])
|
||||
field_value = field_value2
|
||||
if fld_def._type in ('one2many'):
|
||||
obj = self.pool.get(fld_def._obj)
|
||||
obj = self.pool.get(fld_def.model_name)
|
||||
field_value2 = []
|
||||
for i in range(len(field_value or [])):
|
||||
field_value2.append({})
|
||||
for field2 in field_value[i]:
|
||||
if obj._columns[field2]._type \
|
||||
in ('many2one',):
|
||||
obj2 = self.pool.get(obj._columns[field2]._obj)
|
||||
obj2 = self.pool.get(
|
||||
obj._columns[field2].model_name)
|
||||
if not hasattr(obj2, 'search') \
|
||||
or not obj2.search(cursor, user, [
|
||||
('id', '=', field_value[i][field2]),
|
||||
@@ -520,7 +524,7 @@ class Model(object):
|
||||
val.update(getattr(self, 'on_change_' + field)(cursor, user,
|
||||
[], args, context=context))
|
||||
if self._columns[field]._type in ('one2many',):
|
||||
obj = self.pool.get(self._columns[field]._obj)
|
||||
obj = self.pool.get(self._columns[field].model_name)
|
||||
for val2 in res[field]:
|
||||
val2.update(obj._default_on_change(cursor, user,
|
||||
val2, context=context))
|
||||
@@ -648,12 +652,13 @@ class Model(object):
|
||||
'many2many',
|
||||
'many2one',
|
||||
):
|
||||
res[field]['relation'] = copy.copy(self._columns[field]._obj)
|
||||
res[field]['domain'] = copy.copy(self._columns[field]._domain)
|
||||
res[field]['context'] = copy.copy(self._columns[field]._context)
|
||||
if res[field]['type'] == 'one2many':
|
||||
res[field]['relation'] = copy.copy(self._columns[field].model_name)
|
||||
res[field]['domain'] = copy.copy(self._columns[field].domain)
|
||||
res[field]['context'] = copy.copy(self._columns[field].context)
|
||||
if res[field]['type'] == 'one2many' \
|
||||
and hasattr(self._columns[field], 'field'):
|
||||
res[field]['relation_field'] = copy.copy(
|
||||
self._columns[field]._field)
|
||||
self._columns[field].field)
|
||||
|
||||
if fields_names:
|
||||
# filter out fields which aren't in the fields_names list
|
||||
|
||||
+82
-74
@@ -2,9 +2,10 @@
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
|
||||
from trytond.model import ModelStorage, OPERATORS
|
||||
from trytond.osv import fields
|
||||
from trytond.model import fields
|
||||
from trytond.sql_db import table_handler
|
||||
from trytond.netsvc import LocalService
|
||||
from trytond.backend import FIELDS
|
||||
import datetime
|
||||
|
||||
|
||||
@@ -39,20 +40,22 @@ class ModelDB(ModelStorage):
|
||||
|
||||
# create/update table in the database
|
||||
table = table_handler(cursor, self._table, self._name, module_name)
|
||||
datetime_field = FIELDS['datetime']
|
||||
integer_field = FIELDS['integer']
|
||||
logs = (
|
||||
('create_date', 'timestamp', 'TIMESTAMP',
|
||||
fields.DateTime._symbol_set, lambda *a: datetime.datetime.now()),
|
||||
('write_date', 'timestamp', 'TIMESTAMP',
|
||||
fields.DateTime._symbol_set, None),
|
||||
('create_uid', 'int4',
|
||||
'INTEGER REFERENCES res_user ON DELETE SET NULL',
|
||||
fields.Integer._symbol_set, lambda *a: 0),
|
||||
('write_uid', 'int4',
|
||||
'INTEGER REFERENCES res_user ON DELETE SET NULL',
|
||||
fields.Integer._symbol_set, None),
|
||||
('create_date', datetime_field.sql_type(None), datetime_field.symbol_c,
|
||||
datetime_field.symbol_f, lambda *a: datetime.datetime.now()),
|
||||
('write_date', datetime_field.sql_type(None), datetime_field.symbol_c,
|
||||
datetime_field.symbol_f, None),
|
||||
('create_uid', (integer_field.sql_type(None)[0],
|
||||
'INTEGER REFERENCES res_user ON DELETE SET NULL',),
|
||||
integer_field.symbol_c, integer_field.symbol_f, lambda *a: 0),
|
||||
('write_uid', (integer_field.sql_type(None)[0],
|
||||
'INTEGER REFERENCES res_user ON DELETE SET NULL'),
|
||||
integer_field.symbol_c, integer_field.symbol_f, None),
|
||||
)
|
||||
for log in logs:
|
||||
table.add_raw_column(log[0], (log[1], log[2]), log[3],
|
||||
table.add_raw_column(log[0], log[1], (log[2], log[3]),
|
||||
default_fun=log[4], migrate=False)
|
||||
for field_name, field in self._columns.iteritems():
|
||||
default_fun = None
|
||||
@@ -65,7 +68,7 @@ class ModelDB(ModelStorage):
|
||||
):
|
||||
continue
|
||||
|
||||
if field._classic_write:
|
||||
if not hasattr(field, 'set'):
|
||||
if field_name in self._defaults:
|
||||
default_fun = self._defaults[field_name]
|
||||
|
||||
@@ -82,17 +85,20 @@ class ModelDB(ModelStorage):
|
||||
return unpack_result
|
||||
default_fun = unpack_wrapper(default_fun)
|
||||
|
||||
table.add_raw_column(field_name, field.sql_type(),
|
||||
field._symbol_set, default_fun, field.size)
|
||||
table.add_raw_column(field_name,
|
||||
FIELDS[field._type].sql_type(field),
|
||||
(FIELDS[field._type].symbol_c,
|
||||
FIELDS[field._type].symbol_f), default_fun,
|
||||
hasattr(field, 'size') and field.size or None)
|
||||
|
||||
if isinstance(field, (fields.Integer, fields.Float)):
|
||||
table.db_default(field_name, 0)
|
||||
|
||||
if isinstance(field, fields.Many2One):
|
||||
if field._obj in ('res.user', 'res.group'):
|
||||
ref = field._obj.replace('.','_')
|
||||
if field.model_name in ('res.user', 'res.group'):
|
||||
ref = field.model_name.replace('.','_')
|
||||
else:
|
||||
ref = self.pool.get(field._obj)._table
|
||||
ref = self.pool.get(field.model_name)._table
|
||||
table.add_fk(field_name, ref, field.ondelete)
|
||||
|
||||
table.index_action(
|
||||
@@ -106,12 +112,12 @@ class ModelDB(ModelStorage):
|
||||
field_name, action=required and 'add' or 'remove')
|
||||
|
||||
elif isinstance(field, fields.Many2Many):
|
||||
if field._obj in ('res.user', 'res.group'):
|
||||
ref = field._obj.replace('.','_')
|
||||
if field.model_name in ('res.user', 'res.group'):
|
||||
ref = field.model_name.replace('.','_')
|
||||
else:
|
||||
ref = self.pool.get(field._obj)._table
|
||||
table.add_m2m(field_name, ref, field._rel, field.origin,
|
||||
field.target, field.ondelete_origin,
|
||||
ref = self.pool.get(field.model_name)._table
|
||||
table.add_m2m(field_name, ref, field.relation_name,
|
||||
field.origin, field.target, field.ondelete_origin,
|
||||
field.ondelete_target)
|
||||
|
||||
elif not isinstance(field, (fields.One2Many, fields.Function)):
|
||||
@@ -119,7 +125,7 @@ class ModelDB(ModelStorage):
|
||||
|
||||
for field_name, field in self._columns.iteritems():
|
||||
if isinstance(field, fields.Many2One) \
|
||||
and field._obj == self._name \
|
||||
and field.model_name == self._name \
|
||||
and field.left and field.right:
|
||||
self._rebuild_tree(cursor, 0, field_name, False, 0)
|
||||
|
||||
@@ -204,14 +210,16 @@ class ModelDB(ModelStorage):
|
||||
|
||||
# Insert record
|
||||
for field in values:
|
||||
if self._columns[field]._classic_write:
|
||||
if not hasattr(self._columns[field], 'set'):
|
||||
upd0 = upd0 + ',"' + field + '"'
|
||||
upd1 = upd1 + ',' + self._columns[field]._symbol_set[0]
|
||||
upd2.append(self._columns[field]._symbol_set[1](values[field]))
|
||||
upd1 = upd1 + ',' + FIELDS[self._columns[field]._type].symbol_c
|
||||
upd2.append(FIELDS[self._columns[field]._type].symbol_f(
|
||||
values[field]))
|
||||
else:
|
||||
upd_todo.append(field)
|
||||
if field in self._columns \
|
||||
and hasattr(self._columns[field], 'selection') \
|
||||
and self._columns[field].selection \
|
||||
and values[field]:
|
||||
if self._columns[field]._type == 'reference':
|
||||
val = values[field].split(',')[0]
|
||||
@@ -241,8 +249,8 @@ class ModelDB(ModelStorage):
|
||||
upd_todo.sort(lambda x, y: self._columns[x].priority - \
|
||||
self._columns[y].priority)
|
||||
for field in upd_todo:
|
||||
self._columns[field].set(cursor, self, id_new, field, values[field],
|
||||
user=user, context=context)
|
||||
self._columns[field].set(cursor, user, id_new, self, field, values[field],
|
||||
context=context)
|
||||
|
||||
self._validate(cursor, user, [id_new], context=context)
|
||||
|
||||
@@ -250,7 +258,7 @@ class ModelDB(ModelStorage):
|
||||
for k in self._columns:
|
||||
field = self._columns[k]
|
||||
if isinstance(field, fields.Many2One) \
|
||||
and field._obj == self._name \
|
||||
and field.model_name == self._name \
|
||||
and field.left and field.right:
|
||||
self._update_tree(cursor, user, id_new, k, field.left, field.right)
|
||||
|
||||
@@ -284,9 +292,8 @@ class ModelDB(ModelStorage):
|
||||
context=context)
|
||||
|
||||
# all inherited fields + all non inherited fields
|
||||
# for which the attribute whose name is in load is True
|
||||
fields_pre = [x for x in fields_names if (x in self._columns \
|
||||
and getattr(self._columns[x], '_classic_write')) or \
|
||||
and not hasattr(self._columns[x], 'set')) or \
|
||||
(x == '_timestamp')] + \
|
||||
self._inherits.values()
|
||||
|
||||
@@ -395,20 +402,20 @@ class ModelDB(ModelStorage):
|
||||
for field in fields_post:
|
||||
if isinstance(self._columns[field], fields.Function) \
|
||||
and not isinstance(self._columns[field], fields.Property):
|
||||
key = (self._columns[field]._fnct, self._columns[field]._arg)
|
||||
key = (self._columns[field].fnct, self._columns[field].arg)
|
||||
func_fields.setdefault(key, [])
|
||||
func_fields[key].append(field)
|
||||
continue
|
||||
# get the value of that field for all records/ids
|
||||
res2 = self._columns[field].get(cursor, self, ids, field, user,
|
||||
context=context, values=res)
|
||||
res2 = self._columns[field].get(cursor, user, ids, self, field,
|
||||
values=res, context=context)
|
||||
for record in res:
|
||||
record[field] = res2[record['id']]
|
||||
for i in func_fields:
|
||||
field_list = func_fields[i]
|
||||
field = field_list[0]
|
||||
res2 = self._columns[field].get(cursor, self, ids, field_list, user,
|
||||
context=context, values=res)
|
||||
res2 = self._columns[field].get(cursor, user, ids, self, field_list,
|
||||
values=res, context=context)
|
||||
for field in res2:
|
||||
for record in res:
|
||||
record[field] = res2[field][record['id']]
|
||||
@@ -439,7 +446,7 @@ class ModelDB(ModelStorage):
|
||||
for k in self._columns:
|
||||
field = self._columns[k]
|
||||
if isinstance(field, fields.Many2One) \
|
||||
and field._obj == self._name \
|
||||
and field.model_name == self._name \
|
||||
and field.left and field.right:
|
||||
update_tree = True
|
||||
if update_tree:
|
||||
@@ -487,12 +494,12 @@ class ModelDB(ModelStorage):
|
||||
direct = []
|
||||
for field in values:
|
||||
if field in self._columns:
|
||||
if self._columns[field]._classic_write:
|
||||
if not hasattr(self._columns[field], 'set'):
|
||||
if (not self._columns[field].translate) \
|
||||
or (context.get('language') or 'en_US') == 'en_US':
|
||||
upd0.append('"' + field + '"=' + \
|
||||
self._columns[field]._symbol_set[0])
|
||||
upd1.append(self._columns[field]._symbol_set[1](
|
||||
FIELDS[self._columns[field]._type].symbol_c)
|
||||
upd1.append(FIELDS[self._columns[field]._type].symbol_f(
|
||||
values[field]))
|
||||
direct.append(field)
|
||||
else:
|
||||
@@ -501,6 +508,7 @@ class ModelDB(ModelStorage):
|
||||
updend.append(field)
|
||||
if field in self._columns \
|
||||
and hasattr(self._columns[field], 'selection') \
|
||||
and self._columns[field].selection \
|
||||
and values[field]:
|
||||
if self._columns[field]._type == 'reference':
|
||||
val = values[field].split(',')[0]
|
||||
@@ -572,8 +580,8 @@ class ModelDB(ModelStorage):
|
||||
self._columns[y].priority)
|
||||
for field in upd_todo:
|
||||
for select_id in ids:
|
||||
self._columns[field].set(cursor, self, select_id, field,
|
||||
values[field], user, context=context)
|
||||
self._columns[field].set(cursor, user, select_id, self, field,
|
||||
values[field], context=context)
|
||||
|
||||
for table in self._inherits:
|
||||
col = self._inherits[table]
|
||||
@@ -599,7 +607,7 @@ class ModelDB(ModelStorage):
|
||||
for k in self._columns:
|
||||
field = self._columns[k]
|
||||
if isinstance(field, fields.Many2One) \
|
||||
and field._obj == self._name \
|
||||
and field.model_name == self._name \
|
||||
and field.left and field.right:
|
||||
if field.left in values or field.right in values:
|
||||
raise Exception('ValidateError', 'You can not update fields: ' \
|
||||
@@ -676,7 +684,7 @@ class ModelDB(ModelStorage):
|
||||
for k in self._columns:
|
||||
field = self._columns[k]
|
||||
if isinstance(field, fields.Many2One) \
|
||||
and field._obj == self._name \
|
||||
and field.model_name == self._name \
|
||||
and field.left and field.right:
|
||||
cursor.execute('SELECT id FROM "' + self._table + '" '\
|
||||
'WHERE "' + k + '" IN (' \
|
||||
@@ -886,7 +894,7 @@ class ModelDB(ModelStorage):
|
||||
if len(fargs) > 1:
|
||||
if field._type == 'many2one':
|
||||
domain[i] = (fargs[0], 'inselect',
|
||||
self.pool.get(field._obj).search(cursor, user,
|
||||
self.pool.get(field.model_name).search(cursor, user,
|
||||
[(fargs[1], domain[i][1], domain[i][2])],
|
||||
context=context, query_string=True), table)
|
||||
i += 1
|
||||
@@ -894,7 +902,7 @@ class ModelDB(ModelStorage):
|
||||
else:
|
||||
raise Exception('ValidateError', 'Clause on field "%s" ' \
|
||||
'doesn\'t work on "%s"' % (domain[i][0], self._name))
|
||||
if field._properties:
|
||||
if hasattr(field, 'search'):
|
||||
arg = [domain.pop(i)]
|
||||
j = i
|
||||
while j < len(domain):
|
||||
@@ -902,11 +910,10 @@ class ModelDB(ModelStorage):
|
||||
arg.append(domain.pop(j))
|
||||
else:
|
||||
j += 1
|
||||
if field._fnct_search:
|
||||
domain.extend(field.search(cursor, user, table,
|
||||
arg[0][0], arg, context=context))
|
||||
domain.extend(field.search(cursor, user, table,
|
||||
arg[0][0], arg, context=context))
|
||||
elif field._type == 'one2many':
|
||||
field_obj = self.pool.get(field._obj)
|
||||
field_obj = self.pool.get(field.model_name)
|
||||
|
||||
if isinstance(domain[i][2], basestring):
|
||||
# get the ids of the records of the "distant" resource
|
||||
@@ -922,9 +929,9 @@ class ModelDB(ModelStorage):
|
||||
table_query = '(' + table_query + ') AS '
|
||||
|
||||
if ids2 == True or ids2 == False:
|
||||
query1 = 'SELECT "' + field._field + '" ' \
|
||||
query1 = 'SELECT "' + field.field + '" ' \
|
||||
'FROM ' + table_query + '"' + field_obj._table + '" ' \
|
||||
'WHERE "' + field._field + '" IS NOT NULL'
|
||||
'WHERE "' + field.field + '" IS NOT NULL'
|
||||
query2 = table_args
|
||||
clause = 'inselect'
|
||||
if ids2 == False:
|
||||
@@ -934,7 +941,7 @@ class ModelDB(ModelStorage):
|
||||
domain[i] = ('id', '=', '0')
|
||||
else:
|
||||
if len(ids2) < cursor.IN_MAX:
|
||||
query1 = 'SELECT "' + field._field + '" ' \
|
||||
query1 = 'SELECT "' + field.field + '" ' \
|
||||
'FROM ' + table_query + '"' + field_obj._table + '" ' \
|
||||
'WHERE id IN (' + \
|
||||
','.join(['%s' for x in ids2]) + ')'
|
||||
@@ -945,7 +952,7 @@ class ModelDB(ModelStorage):
|
||||
for i in range(0, len(ids2), cursor.IN_MAX):
|
||||
sub_ids2 = ids2[i:i + cursor.IN_MAX]
|
||||
cursor.execute(
|
||||
'SELECT "' + field._field + \
|
||||
'SELECT "' + field.field + \
|
||||
'" FROM ' + table_query + '"' + field_obj._table + '" ' \
|
||||
'WHERE id IN (' + \
|
||||
','.join(['%s' for x in sub_ids2]) + ')',
|
||||
@@ -960,7 +967,7 @@ class ModelDB(ModelStorage):
|
||||
if domain[i][1] in ('child_of', 'not child_of'):
|
||||
if isinstance(domain[i][2], basestring):
|
||||
ids2 = [x[0] for x in self.pool.get(
|
||||
field._obj).name_search(cursor, user, domain[i][2], [],
|
||||
field.model_name).name_search(cursor, user, domain[i][2], [],
|
||||
'like', context=context)]
|
||||
elif isinstance(domain[i][2], (int, long)):
|
||||
ids2 = [domain[i][2]]
|
||||
@@ -975,16 +982,16 @@ class ModelDB(ModelStorage):
|
||||
context=context)
|
||||
return ids + _rec_get(ids2, table, parent)
|
||||
|
||||
if field._obj != table._name:
|
||||
if field.model_name != table._name:
|
||||
if len(domain[i]) != 4:
|
||||
raise Exception('Error', 'Programming error: ' \
|
||||
'child_of on field "%s" is not allowed!' % \
|
||||
(domain[i][0],))
|
||||
ids2 = self.pool.get(field._obj).search(cursor, user,
|
||||
ids2 = self.pool.get(field.model_name).search(cursor, user,
|
||||
[(domain[i][3], 'child_of', ids2)],
|
||||
context=context)
|
||||
query1 = 'SELECT "' + field.origin + '" ' \
|
||||
'FROM "' + field._rel + '" ' \
|
||||
'FROM "' + field.relation_name + '" ' \
|
||||
'WHERE "' + field.target + '" IN (' + \
|
||||
','.join(['%s' for x in ids2]) + ') ' \
|
||||
'AND "' + field.origin + '" IS NOT NULL'
|
||||
@@ -1002,14 +1009,14 @@ class ModelDB(ModelStorage):
|
||||
table, domain[i][0]))
|
||||
else:
|
||||
if isinstance(domain[i][2], basestring):
|
||||
res_ids = [x[0] for x in self.pool.get(field._obj
|
||||
res_ids = [x[0] for x in self.pool.get(field.model_name
|
||||
).name_search(cursor, user, domain[i][2], [],
|
||||
domain[i][1], context=context)]
|
||||
else:
|
||||
res_ids = domain[i][2]
|
||||
if res_ids == True or res_ids == False:
|
||||
query1 = 'SELECT "' + field.origin + '" ' \
|
||||
'FROM "' + field._rel + '" '\
|
||||
'FROM "' + field.relation_name + '" '\
|
||||
'WHERE "' + field.origin + '" IS NOT NULL'
|
||||
query2 = []
|
||||
clause = 'inselect'
|
||||
@@ -1020,7 +1027,7 @@ class ModelDB(ModelStorage):
|
||||
domain[i] = ('id', '=', '0')
|
||||
else:
|
||||
query1 = 'SELECT "' + field.origin + '" ' \
|
||||
'FROM "' + field._rel + '" ' \
|
||||
'FROM "' + field.relation_name + '" ' \
|
||||
'WHERE "' + field.target + '" IN (' + \
|
||||
','.join(['%s' for x in res_ids]) + ')'
|
||||
query2 = [str(x) for x in res_ids]
|
||||
@@ -1032,7 +1039,7 @@ class ModelDB(ModelStorage):
|
||||
if domain[i][1] in ('child_of', 'not child_of'):
|
||||
if isinstance(domain[i][2], basestring):
|
||||
ids2 = [x[0] for x in self.pool.get(
|
||||
field._obj).name_search(cursor, user, domain[i][2],
|
||||
field.model_name).name_search(cursor, user, domain[i][2],
|
||||
[], 'like', context=context)]
|
||||
elif isinstance(domain[i][2], (int, long)):
|
||||
ids2 = [domain[i][2]]
|
||||
@@ -1047,12 +1054,12 @@ class ModelDB(ModelStorage):
|
||||
context=context)
|
||||
return ids + _rec_get(ids2, table, parent)
|
||||
|
||||
if field._obj != table._name:
|
||||
if field.model_name != table._name:
|
||||
if len(domain[i]) != 4:
|
||||
raise Exception('Error', 'Programming error: ' \
|
||||
'child_of on field "%s" is not allowed!' % \
|
||||
(domain[i][0],))
|
||||
ids2 = self.pool.get(field._obj).search(cursor, user,
|
||||
ids2 = self.pool.get(field.model_name).search(cursor, user,
|
||||
[(domain[i][3], 'child_of', ids2)],
|
||||
context=context)
|
||||
if domain[i][1] == 'child_of':
|
||||
@@ -1090,7 +1097,7 @@ class ModelDB(ModelStorage):
|
||||
ids2, table, domain[i][0]), table)
|
||||
else:
|
||||
if isinstance(domain[i][2], basestring):
|
||||
res_ids = self.pool.get(field._obj).name_search(cursor,
|
||||
res_ids = self.pool.get(field.model_name).name_search(cursor,
|
||||
user, domain[i][2], [], domain[i][1],
|
||||
context=context)
|
||||
domain[i] = (domain[i][0], 'in', [x[0] for x in res_ids],
|
||||
@@ -1194,10 +1201,11 @@ class ModelDB(ModelStorage):
|
||||
(table._table,
|
||||
','.join(['%s'] * len(arg2)),))
|
||||
else:
|
||||
symbol_c = FIELDS[table._columns[arg[0]]._type]\
|
||||
.symbol_c
|
||||
qu1.append(('(%s.%s ' + arg[1] + ' (%s))') % \
|
||||
(table._table, arg[0], ','.join(
|
||||
[table._columns[arg[0]].\
|
||||
_symbol_set[0]] * len(arg2))))
|
||||
[symbol_c] * len(arg2))))
|
||||
if todel:
|
||||
if table._columns[arg[0]]._type == 'boolean':
|
||||
if arg[1] == 'in':
|
||||
@@ -1263,8 +1271,8 @@ class ModelDB(ModelStorage):
|
||||
add_null = True
|
||||
else:
|
||||
if arg[0] in table._columns:
|
||||
qu2.append(table._columns[arg[0]].\
|
||||
_symbol_set[1](arg[2]))
|
||||
qu2.append(FIELDS[table._columns[arg[0]]._type].\
|
||||
symbol_f(arg[2]))
|
||||
if arg[0] in table._columns:
|
||||
if arg[1] in ('like', 'ilike'):
|
||||
qu1.append('(%s.%s %s %s OR %s.%s %s %s)' % \
|
||||
@@ -1276,8 +1284,8 @@ class ModelDB(ModelStorage):
|
||||
table._table, arg[0], arg[1], '%s'))
|
||||
else:
|
||||
qu1.append('(%s.%s %s %s)' % (table._table,
|
||||
arg[0], arg[1],
|
||||
table._columns[arg[0]]._symbol_set[0]))
|
||||
arg[0], arg[1], FIELDS[table._columns[
|
||||
arg[0]]._type].symbol_c))
|
||||
else:
|
||||
if arg[1] in ('like', 'ilike'):
|
||||
qu1.append('(%s.%s %s \'%s\' or %s.%s %s \'%s\')' % \
|
||||
@@ -1310,14 +1318,14 @@ class ModelDB(ModelStorage):
|
||||
if field in self._columns:
|
||||
table_name = self._table
|
||||
|
||||
if self._columns[field]._classic_write:
|
||||
if not hasattr(self._columns[field], 'set'):
|
||||
field_name = field
|
||||
|
||||
if self._columns[field].order_field:
|
||||
field_name = self._columns[field].order_field
|
||||
|
||||
if isinstance(self._columns[field], fields.Many2One):
|
||||
obj = self.pool.get(self._columns[field]._obj)
|
||||
obj = self.pool.get(self._columns[field].model_name)
|
||||
table_name = obj._table
|
||||
link_field = field
|
||||
field_name = None
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
from trytond.model import Model
|
||||
from trytond.osv import fields
|
||||
from trytond.model import fields
|
||||
from trytond.model.browse import BrowseRecordList, BrowseRecord, BrowseRecordNull
|
||||
from trytond.model.browse import EvalEnvironment
|
||||
import datetime
|
||||
@@ -789,9 +789,9 @@ class ModelStorage(Model):
|
||||
for field_name, field in self._columns.iteritems():
|
||||
# validate domain
|
||||
if field._type in ('many2one', 'many2many', 'one2many') \
|
||||
and field._domain:
|
||||
relation_obj = self.pool.get(field._obj)
|
||||
if isinstance(field._domain, basestring):
|
||||
and field.domain:
|
||||
relation_obj = self.pool.get(field.model_name)
|
||||
if isinstance(field.domain, basestring):
|
||||
ctx = context.copy()
|
||||
ctx.update(ctx_pref)
|
||||
for record in records:
|
||||
@@ -801,7 +801,7 @@ class ModelStorage(Model):
|
||||
env['time'] = time
|
||||
env['context'] = context
|
||||
env['active_id'] = record.id
|
||||
domain = eval(field._domain, env)
|
||||
domain = eval(field.domain, env)
|
||||
relation_ids = []
|
||||
if record[field_name]:
|
||||
if field._type in ('many2one',):
|
||||
@@ -832,7 +832,7 @@ class ModelStorage(Model):
|
||||
find_ids = relation_obj.search(cursor, user, [
|
||||
'AND',
|
||||
[('id', 'in', relation_ids)],
|
||||
field._domain,
|
||||
field.domain,
|
||||
], context=context)
|
||||
if not set(relation_ids) == set(find_ids):
|
||||
self.raise_user_error(cursor,
|
||||
@@ -853,9 +853,6 @@ class ModelStorage(Model):
|
||||
env['active_id'] = record.id
|
||||
required = eval(field.states['required'], env)
|
||||
if required and not record[field_name]:
|
||||
print record[field_name]
|
||||
print field_name
|
||||
print field.states['required']
|
||||
self.raise_user_error(cursor,
|
||||
'required_validation_record',
|
||||
error_args=get_error_args(field_name),
|
||||
@@ -880,7 +877,7 @@ class ModelStorage(Model):
|
||||
else:
|
||||
vals[field] = defaults[field]
|
||||
elif fld_def._type in ('one2many',):
|
||||
obj = self.pool.get(self._columns[field]._obj)
|
||||
obj = self.pool.get(self._columns[field].model_name)
|
||||
vals[field] = []
|
||||
for defaults2 in defaults[field]:
|
||||
vals2 = obj._clean_defaults(defaults2)
|
||||
|
||||
@@ -293,9 +293,11 @@ class ModelView(Model):
|
||||
attrs = {}
|
||||
try:
|
||||
if element.get(attr) in self._columns:
|
||||
relation = self._columns[element.get(attr)]._obj
|
||||
relation = self._columns[element.get(
|
||||
attr)].model_name
|
||||
else:
|
||||
relation = self._inherit_fields[element.get(attr)][2]._obj
|
||||
relation = self._inherit_fields[element.get(
|
||||
attr)][2].model_name
|
||||
except:
|
||||
relation = False
|
||||
if relation and element.tag == 'field':
|
||||
|
||||
+1
-685
@@ -1,687 +1,3 @@
|
||||
#This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
#this repository contains the full copyright notices and license terms.
|
||||
"""
|
||||
Fields:
|
||||
- simple
|
||||
- relations (one2many, many2one, many2many)
|
||||
- function
|
||||
|
||||
Fields Attributes:
|
||||
_classic_read: is a classic sql fields
|
||||
_type : field type
|
||||
readonly
|
||||
required
|
||||
size
|
||||
|
||||
Relationals fields
|
||||
|
||||
Values: ('create', { fields }) create
|
||||
('write', ids, { fields }) modification
|
||||
('delete', ids) remove (delete)
|
||||
('unlink', ids) unlink one (target id or target of relation)
|
||||
('add', ids) link
|
||||
('unlink_all') unlink all
|
||||
('set', ids) set a list of links
|
||||
"""
|
||||
|
||||
import psycopg2
|
||||
import warnings
|
||||
import __builtin__
|
||||
import sha
|
||||
import inspect
|
||||
|
||||
def _symbol_f(symb):
|
||||
if symb is None or symb == False:
|
||||
return None
|
||||
elif isinstance(symb, str):
|
||||
return unicode(symb, 'utf-8')
|
||||
elif isinstance(symb, unicode):
|
||||
return symb
|
||||
return unicode(symb)
|
||||
|
||||
class Column(object):
|
||||
_classic_read = True
|
||||
_classic_write = True
|
||||
_properties = False
|
||||
_type = 'unknown'
|
||||
_obj = None
|
||||
_symbol_c = '%s'
|
||||
_symbol_f = _symbol_f
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
|
||||
def __init__(self, string='unknown', required=False, readonly=False,
|
||||
domain=None, context='', states=None, priority=0,
|
||||
change_default=False, size=None, ondelete="SET NULL",
|
||||
translate=False, select=0, on_change=None, on_change_with=None,
|
||||
depends=None, **args):
|
||||
self.states = states or {}
|
||||
self.string = string
|
||||
self.readonly = readonly
|
||||
self.required = required
|
||||
self.size = size
|
||||
self.help = args.get('help', '')
|
||||
self.priority = priority
|
||||
self.change_default = change_default
|
||||
self.ondelete = ondelete
|
||||
self.translate = translate
|
||||
self._domain = domain or []
|
||||
self._context = context
|
||||
self.depends = depends or []
|
||||
if select not in (0, 1, 2):
|
||||
raise Exception('Error', 'Select must be one of 0, 1, 2')
|
||||
self.select = select
|
||||
self.on_change = on_change
|
||||
self.on_change_with = on_change_with
|
||||
self.order_field = None
|
||||
for i in args:
|
||||
if args[i]:
|
||||
setattr(self, i, args[i])
|
||||
|
||||
def sql_type(self):
|
||||
raise Exception('undefined sql_type method!')
|
||||
|
||||
|
||||
class Boolean(Column):
|
||||
_type = 'boolean'
|
||||
_symbol_c = '%s'
|
||||
_symbol_f = lambda x: x and 'True' or 'False'
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
|
||||
def sql_type(self):
|
||||
return ('bool', 'bool')
|
||||
|
||||
|
||||
class Integer(Column):
|
||||
_type = 'integer'
|
||||
_symbol_c = '%s'
|
||||
_symbol_f = lambda x: int(x or 0)
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
|
||||
def sql_type(self):
|
||||
return ('int4', 'int4')
|
||||
|
||||
|
||||
class BigInteger(Integer):
|
||||
_type = 'biginteger'
|
||||
|
||||
def sql_type(self):
|
||||
return ('int8', 'int8')
|
||||
|
||||
|
||||
class Reference(Column):
|
||||
_type = 'reference'
|
||||
_classic_read = False
|
||||
|
||||
def __init__(self, string, selection, size=None, **args):
|
||||
Column.__init__(self, string=string, size=size, selection=selection,
|
||||
**args)
|
||||
|
||||
def get(self, cursor, obj, ids, name, user=None, offset=0, context=None,
|
||||
values=None):
|
||||
if values is None:
|
||||
values = {}
|
||||
res = {}
|
||||
for i in values:
|
||||
res[i['id']] = i[name]
|
||||
for i in ids:
|
||||
if not (i in res):
|
||||
res[i] = False
|
||||
continue
|
||||
if not res[i]:
|
||||
continue
|
||||
ref_model, ref_id = res[i].split(',', 1)
|
||||
if not ref_model:
|
||||
continue
|
||||
ref_obj = obj.pool.get(ref_model)
|
||||
if not ref_obj:
|
||||
continue
|
||||
try:
|
||||
ref_id = eval(ref_id)
|
||||
except:
|
||||
pass
|
||||
try:
|
||||
ref_id = int(ref_id)
|
||||
except:
|
||||
continue
|
||||
if ref_id \
|
||||
and not ref_obj.search(cursor, user, [
|
||||
('id', '=', ref_id),
|
||||
], context=context):
|
||||
ref_id = False
|
||||
if ref_id:
|
||||
ref_name = ref_obj.name_get(cursor, user, ref_id,
|
||||
context=context)
|
||||
if ref_name:
|
||||
ref_name = ref_name[0][1]
|
||||
else:
|
||||
ref_name = ''
|
||||
else:
|
||||
ref_name = ''
|
||||
res[i] = ref_model + ',(' + str(ref_id) + ',"' + ref_name + '")'
|
||||
return res
|
||||
|
||||
def sql_type(self):
|
||||
if self.size:
|
||||
return ('varchar', 'varchar(%d)' % (self.size,))
|
||||
else:
|
||||
return ('varchar', 'varchar')
|
||||
|
||||
|
||||
class Char(Column):
|
||||
_type = 'char'
|
||||
|
||||
def __init__(self, string, size=None, **args):
|
||||
Column.__init__(self, string=string, size=size, **args)
|
||||
|
||||
def sql_type(self):
|
||||
if self.size:
|
||||
return ('varchar', 'varchar(%d)' % (self.size,))
|
||||
else:
|
||||
return ('varchar', 'varchar')
|
||||
|
||||
|
||||
class Sha(Column):
|
||||
_type = 'sha'
|
||||
|
||||
def __init__(self, string, **args):
|
||||
Column.__init__(self, string=string, size=40, **args)
|
||||
self._symbol_f = lambda x: x and sha.new(x).hexdigest() or ''
|
||||
self._symbol_set = (self._symbol_c, self._symbol_f)
|
||||
|
||||
def sql_type(self):
|
||||
return ('varchar', 'varchar(40)')
|
||||
|
||||
|
||||
class Text(Column):
|
||||
_type = 'text'
|
||||
|
||||
def sql_type(self):
|
||||
return ('text', 'text')
|
||||
|
||||
|
||||
class Float(Column):
|
||||
_type = 'float'
|
||||
_symbol_c = '%s'
|
||||
_symbol_f = lambda x: __builtin__.float(x or 0.0)
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
|
||||
def __init__(self, string='unknown', digits=None, **args):
|
||||
Column.__init__(self, string=string, **args)
|
||||
self.digits = digits
|
||||
|
||||
def sql_type(self):
|
||||
return ('float8', 'float8')
|
||||
|
||||
|
||||
class Numeric(Float):
|
||||
_type = 'numeric'
|
||||
|
||||
def sql_type(self):
|
||||
return ('numeric', 'numeric')
|
||||
|
||||
|
||||
class Date(Column):
|
||||
_type = 'date'
|
||||
|
||||
def sql_type(self):
|
||||
return ('date', 'date')
|
||||
|
||||
|
||||
class DateTime(Column):
|
||||
_type = 'datetime'
|
||||
|
||||
def sql_type(self):
|
||||
return ('timestamp', 'timestamp(0)')
|
||||
|
||||
|
||||
class Time(Column):
|
||||
_type = 'time'
|
||||
|
||||
def sql_type(self):
|
||||
return ('time', 'time')
|
||||
|
||||
|
||||
class Binary(Column):
|
||||
_type = 'binary'
|
||||
_symbol_c = '%s'
|
||||
_symbol_f = lambda symb: symb and psycopg2.Binary(symb) or None
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
|
||||
def sql_type(self):
|
||||
return ('bytea', 'bytea')
|
||||
|
||||
|
||||
class Selection(Column):
|
||||
_type = 'selection'
|
||||
|
||||
def __init__(self, selections, string='unknown', sort=True, translate=True,
|
||||
**args):
|
||||
"""
|
||||
selections is a list of (key, string)
|
||||
or the name of the object function that return the list
|
||||
"""
|
||||
self.sort = sort
|
||||
self.translate_selection = translate
|
||||
Column.__init__(self, string=string, selection=selections, **args)
|
||||
|
||||
def sql_type(self):
|
||||
if self.size:
|
||||
return ('varchar', 'varchar(%d)' % (self.size,))
|
||||
else:
|
||||
return ('varchar', 'varchar')
|
||||
|
||||
|
||||
class Many2One(Column):
|
||||
_classic_read = False
|
||||
_classic_write = True
|
||||
_type = 'many2one'
|
||||
_symbol_c = '%s'
|
||||
_symbol_f = lambda x: x and int(x) or None
|
||||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
|
||||
def __init__(self, obj, string='unknown', left=None, right=None, **args):
|
||||
Column.__init__(self, string=string, **args)
|
||||
self._obj = obj
|
||||
self.left = left
|
||||
self.right = right
|
||||
|
||||
def get(self, cursor, obj, ids, name, user=None, offset=0, context=None,
|
||||
values=None):
|
||||
if values is None:
|
||||
values = {}
|
||||
res = {}
|
||||
for i in values:
|
||||
res[i['id']] = i[name]
|
||||
for i in ids:
|
||||
res.setdefault(i, '')
|
||||
try:
|
||||
obj = obj.pool.get(self._obj)
|
||||
except KeyError:
|
||||
return res
|
||||
obj_names = {}
|
||||
for obj_id, name in obj.name_get(cursor, user,
|
||||
[isinstance(x, (list, tuple)) and x[0] or x
|
||||
for x in res.values() if x],
|
||||
context=context):
|
||||
obj_names[obj_id] = name
|
||||
|
||||
for i in res.keys():
|
||||
if res[i] and res[i] in obj_names:
|
||||
res[i] = (res[i], obj_names[res[i]])
|
||||
else:
|
||||
res[i] = False
|
||||
return res
|
||||
|
||||
def set(self, cursor, obj_src, obj_id, field, values, user=None,
|
||||
context=None):
|
||||
obj = obj_src.pool.get(self._obj)
|
||||
table = obj_src.pool.get(self._obj)._table
|
||||
if type(values) == type([]):
|
||||
for act in values:
|
||||
if act[0] == 'create':
|
||||
id_new = obj.create(cursor, user, act[2], context=context)
|
||||
cursor.execute('UPDATE "' + obj_src._table + '" ' \
|
||||
'SET "' + field + '" = %s ' \
|
||||
'WHERE id = %s', (id_new, obj_id))
|
||||
elif act[0] == 'write':
|
||||
obj.write(cursor, act[1], act[2], context=context)
|
||||
elif act[0] == 'delete':
|
||||
obj.delete(cursor, user, act[1], context=context)
|
||||
cursor.execute('DELETE FROM "' + table + '" ' \
|
||||
'WHERE id = %s', (act[1],))
|
||||
elif act[0] == 'unlink' or act[0] == 'unlink_all':
|
||||
cursor.execute('UPDATE "' + obj_src._table + '" ' \
|
||||
'SET "' + field + '" = NULL ' \
|
||||
'WHERE id = %s', (obj_id,))
|
||||
elif act[0] == 'add':
|
||||
cursor.execute('UPDATE "' + obj_src._table + '" ' \
|
||||
'SET "' + field + '" = %s ' \
|
||||
'WHERE id = %s', (act[1], obj_id))
|
||||
else:
|
||||
if values:
|
||||
cursor.execute('UPDATE "' + obj_src._table + '" ' \
|
||||
'SET "' + field + '" = %s ' \
|
||||
'WHERE id = %s', (values, obj_id))
|
||||
else:
|
||||
cursor.execute('UPDATE "' + obj_src._table + '" ' \
|
||||
'SET "' + field + '" = NULL ' \
|
||||
'WHERE id = %s', (obj_id,))
|
||||
|
||||
def sql_type(self):
|
||||
return ('int4', 'int4')
|
||||
|
||||
|
||||
class One2Many(Column):
|
||||
_classic_read = False
|
||||
_classic_write = False
|
||||
_type = 'one2many'
|
||||
|
||||
def __init__(self, obj, field, string='unknown', limit=None, order=None,
|
||||
**args):
|
||||
Column.__init__(self, string=string, **args)
|
||||
self._obj = obj
|
||||
self._field = field
|
||||
self._limit = limit
|
||||
self._order = order
|
||||
#one2many can't be used as condition for defaults
|
||||
assert(self.change_default != True)
|
||||
|
||||
def get(self, cursor, obj, ids, name, user=None, offset=0, context=None,
|
||||
values=None):
|
||||
res = {}
|
||||
for i in ids:
|
||||
res[i] = []
|
||||
ids2 = []
|
||||
for i in range(0, len(ids), cursor.IN_MAX):
|
||||
sub_ids = ids[i:i + cursor.IN_MAX]
|
||||
ids2 += obj.pool.get(self._obj).search(cursor, user,
|
||||
[(self._field, 'in', sub_ids)], order=self._order,
|
||||
context=context)
|
||||
if self._limit and len(ids2) > offset + self._limit:
|
||||
break
|
||||
if offset:
|
||||
ids2 = ids2[offset:]
|
||||
if self._limit:
|
||||
ids2 = ids2[:self._limit]
|
||||
for i in obj.pool.get(self._obj).read(cursor, user, ids2,
|
||||
[self._field], context=context):
|
||||
res[i[self._field][0]].append( i['id'] )
|
||||
return res
|
||||
|
||||
def set(self, cursor, obj, obj_id, field, values, user=None, context=None):
|
||||
if not values:
|
||||
return
|
||||
_table = obj.pool.get(self._obj)._table
|
||||
obj = obj.pool.get(self._obj)
|
||||
for act in values:
|
||||
if act[0] == 'create':
|
||||
act[1][self._field] = obj_id
|
||||
obj.create(cursor, user, act[1], context=context)
|
||||
elif act[0] == 'write':
|
||||
act[2][self._field] = obj_id
|
||||
obj.write(cursor, user, act[1] , act[2], context=context)
|
||||
elif act[0] == 'delete':
|
||||
obj.delete(cursor, user, act[1], context=context)
|
||||
elif act[0] == 'unlink':
|
||||
if isinstance(act[1], (int, long)):
|
||||
ids = [act[1]]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
if not ids:
|
||||
continue
|
||||
ids = obj.search(cursor, user, [
|
||||
(self._field, '=', obj_id),
|
||||
('id', 'in', ids),
|
||||
], context=context)
|
||||
obj.write(cursor, user, ids, {
|
||||
self._field: False,
|
||||
}, context=context)
|
||||
elif act[0] == 'add':
|
||||
if isinstance(act[1], (int, long)):
|
||||
ids = [act[1]]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
if not ids:
|
||||
continue
|
||||
ids = obj.write(cursor, user, ids, {
|
||||
self._field: obj_id,
|
||||
}, context=context)
|
||||
elif act[0] == 'unlink_all':
|
||||
ids = obj.search(cursor, user, [
|
||||
(self._field, '=', obj_id),
|
||||
], context=context)
|
||||
obj.write(cursor, user, ids, {
|
||||
self._field: False,
|
||||
}, context=context)
|
||||
elif act[0] == 'set':
|
||||
if not act[1]:
|
||||
ids = [0]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
ids2 = obj.search(cursor, user, [
|
||||
(self._field, '=', obj_id),
|
||||
('id', 'not in', ids),
|
||||
], context=context)
|
||||
obj.write(cursor, user, ids2, {
|
||||
self._field: False,
|
||||
}, context=context)
|
||||
if act[1]:
|
||||
obj.write(cursor, user, ids, {
|
||||
self._field: obj_id,
|
||||
}, context=context)
|
||||
else:
|
||||
raise Exception('Bad arguments')
|
||||
|
||||
|
||||
class Many2Many(Column):
|
||||
_classic_read = False
|
||||
_classic_write = False
|
||||
_type = 'many2many'
|
||||
|
||||
def __init__(self, obj, rel, origin, target, string='unknown', limit=None,
|
||||
order=None, ondelete_origin='CASCADE', ondelete_target='RESTRICT',
|
||||
**args):
|
||||
Column.__init__(self, string=string, **args)
|
||||
self._obj = obj
|
||||
self._rel = rel
|
||||
self.origin = origin
|
||||
self.ondelete_origin = ondelete_origin
|
||||
self.target = target
|
||||
self.ondelete_target = ondelete_target
|
||||
self._limit = limit
|
||||
self._order = order
|
||||
|
||||
def get(self, cursor, obj, ids, name, user=None, offset=0, context=None,
|
||||
values=None):
|
||||
if values is None:
|
||||
values = {}
|
||||
res = {}
|
||||
if not ids:
|
||||
return res
|
||||
for i in ids:
|
||||
res[i] = []
|
||||
ids_s = ','.join([str(x) for x in ids])
|
||||
limit_str = self._limit is not None and ' limit %s' % self._limit or ''
|
||||
obj = obj.pool.get(self._obj)
|
||||
|
||||
domain1, domain2 = obj.pool.get('ir.rule').domain_get(cursor,
|
||||
user, obj._name, context=context)
|
||||
if domain1:
|
||||
domain1 = ' and '+domain1
|
||||
|
||||
#TODO fix order: can have many fields
|
||||
cursor.execute('SELECT ' + self._rel + '.' + self.target + ', ' + \
|
||||
self._rel + '.' + self.origin + ' ' \
|
||||
'FROM "' + self._rel + '" , "' + obj._table + '" ' \
|
||||
'WHERE ' + \
|
||||
self._rel + '.' + self.origin + ' IN (' + ids_s + ') ' \
|
||||
'AND ' + self._rel + '.' + self.target + ' = ' + \
|
||||
obj._table + '.id ' + domain1 + \
|
||||
limit_str + ' ORDER BY ' + \
|
||||
','.join([obj._table + '.' + x[0] + ' ' + x[1] \
|
||||
for x in (self._order or obj._order)]) + \
|
||||
' OFFSET %s', domain2 + [offset])
|
||||
for i in cursor.fetchall():
|
||||
res[i[1]].append(i[0])
|
||||
return res
|
||||
|
||||
def set(self, cursor, obj, obj_id, name, values, user=None, context=None):
|
||||
if not values:
|
||||
return
|
||||
obj = obj.pool.get(self._obj)
|
||||
for act in values:
|
||||
if act[0] == 'create':
|
||||
idnew = obj.create(cursor, user, act[1], context=context)
|
||||
cursor.execute('INSERT INTO "' + self._rel + '" ' \
|
||||
'(' + self.origin + ', ' + self.target + ') ' \
|
||||
'VALUES (%s, %s)', (obj_id, idnew))
|
||||
elif act[0] == 'write':
|
||||
obj.write(cursor, user, act[1] , act[2], context=context)
|
||||
elif act[0] == 'delete':
|
||||
obj.delete(cursor, user, act[1], context=context)
|
||||
elif act[0] == 'unlink':
|
||||
if isinstance(act[1], (int, long)):
|
||||
ids = [act[1]]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
if not ids:
|
||||
continue
|
||||
cursor.execute('DELETE FROM "' + self._rel + '" ' \
|
||||
'WHERE "' + self.origin + '" = %s ' \
|
||||
'AND "'+ self.target + '" IN (' \
|
||||
+ ','.join(['%s' for x in ids]) + ')',
|
||||
[obj_id] + ids)
|
||||
elif act[0] == 'add':
|
||||
if isinstance(act[1], (int, long)):
|
||||
ids = [act[1]]
|
||||
else:
|
||||
ids = list(act[1])
|
||||
if not ids:
|
||||
continue
|
||||
cursor.execute('SELECT "' + self.target + '" ' \
|
||||
'FROM "' + self._rel + '" ' \
|
||||
'WHERE "' + self.origin + '" = %s ' \
|
||||
'AND "' + self.target + '" IN (' + \
|
||||
','.join(['%s' for x in ids]) + ')',
|
||||
[obj_id] + ids)
|
||||
existing_ids = []
|
||||
for row in cursor.fetchall():
|
||||
existing_ids.append(row[0])
|
||||
new_ids = [x for x in ids if x not in existing_ids]
|
||||
for new_id in new_ids:
|
||||
cursor.execute('INSERT INTO "' + self._rel + '" ' \
|
||||
'("' + self.origin + '", "' + self.target + '") ' \
|
||||
'VALUES (%s, %s)', (obj_id, new_id))
|
||||
elif act[0] == 'unlink_all':
|
||||
cursor.execute('UPDATE "' + self._rel + '" ' \
|
||||
'SET "' + self.target + '" = NULL ' \
|
||||
'WHERE "' + self.target + '" = %s', (obj_id,))
|
||||
elif act[0] == 'set':
|
||||
if not act[1]:
|
||||
ids = []
|
||||
else:
|
||||
ids = list(act[1])
|
||||
domain1, domain2 = obj.pool.get('ir.rule').domain_get(cursor,
|
||||
user, obj._name, context=context)
|
||||
if domain1:
|
||||
domain1 = ' AND ' + domain1
|
||||
cursor.execute('DELETE FROM "' + self._rel + '" ' \
|
||||
'WHERE "' + self.origin + '" = %s ' \
|
||||
'AND "' + self.target + '" IN (' \
|
||||
'SELECT ' + self._rel + '.' + self.target + ' ' \
|
||||
'FROM "' + self._rel + '", "' + obj._table + '" ' \
|
||||
'WHERE ' + self._rel + '.' + self.origin + ' = %s ' \
|
||||
'AND ' + self._rel + '.' + self.target + ' = ' + \
|
||||
obj._table + '.id ' + domain1 + ')',
|
||||
[obj_id, obj_id] + domain2)
|
||||
|
||||
for new_id in ids:
|
||||
cursor.execute('INSERT INTO "' + self._rel + '" ' \
|
||||
'("' + self.origin + '", "' + self.target + '") ' \
|
||||
'VALUES (%s, %s)', (obj_id, new_id))
|
||||
else:
|
||||
raise Exception('Bad arguments')
|
||||
|
||||
|
||||
class Function(Column):
|
||||
_classic_read = False
|
||||
_classic_write = False
|
||||
_properties = True
|
||||
|
||||
def __init__(self, fnct, arg=None, fnct_inv='', fnct_inv_arg=None,
|
||||
type='float', fnct_search='', obj=None, **args):
|
||||
Column.__init__(self, **args)
|
||||
self._obj = obj
|
||||
self._fnct = fnct
|
||||
self._fnct_inv = fnct_inv
|
||||
self._arg = arg
|
||||
self._field = ''
|
||||
self._obj = ''
|
||||
if 'relation' in args:
|
||||
self._obj = args['relation']
|
||||
self._fnct_inv_arg = fnct_inv_arg
|
||||
if not fnct_inv:
|
||||
self.readonly = 1
|
||||
self._type = type
|
||||
self._fnct_search = fnct_search
|
||||
self._symbol_c = _TYPE2CLASS[self._type]._symbol_c
|
||||
self._symbol_f = _TYPE2CLASS[self._type]._symbol_f
|
||||
self._symbol_set = (self._symbol_c, self._symbol_f)
|
||||
|
||||
def search(self, cursor, user, obj, name, args, context=None):
|
||||
if not self._fnct_search:
|
||||
return []
|
||||
return getattr(obj, self._fnct_search)(cursor, user, name, args,
|
||||
context=context)
|
||||
|
||||
def get(self, cursor, obj, ids, name, user=None, offset=0, context=None,
|
||||
values=None):
|
||||
if isinstance(name, list):
|
||||
names = name
|
||||
# Test is the function works with a list of names
|
||||
if 'names' in inspect.getargspec(getattr(obj, self._fnct))[0]:
|
||||
return getattr(obj, self._fnct)(cursor, user, ids, names,
|
||||
self._arg, context=context)
|
||||
res = {}
|
||||
for name in names:
|
||||
res[name] = getattr(obj, self._fnct)(cursor, user, ids, name,
|
||||
self._arg, context=context)
|
||||
return res
|
||||
else:
|
||||
# Test is the function works with a list of names
|
||||
if 'names' in inspect.getargspec(getattr(obj, self._fnct))[0]:
|
||||
name = [name]
|
||||
return getattr(obj, self._fnct)(cursor, user, ids, name, self._arg,
|
||||
context=context)
|
||||
|
||||
def set(self, cursor, obj, obj_id, name, value, user=None, context=None):
|
||||
if self._fnct_inv:
|
||||
getattr(obj, self._fnct_inv)(cursor, user, obj_id, name, value,
|
||||
self._fnct_inv_arg, context=context)
|
||||
|
||||
|
||||
class Property(Function):
|
||||
|
||||
def _fnct_write(self, obj, cursor, user, obj_id, prop, id_val, val,
|
||||
context=None):
|
||||
property_obj = obj.pool.get('ir.property')
|
||||
return property_obj.set(cursor, user, prop, obj._name, obj_id,
|
||||
(id_val and val + ',' + str(id_val)) or False, context=context)
|
||||
|
||||
def _fnct_read(self, obj, cursor, user, ids, prop, arg, context=None):
|
||||
property_obj = obj.pool.get('ir.property')
|
||||
res = property_obj.get(cursor, user, prop, obj._name, ids,
|
||||
context=context)
|
||||
|
||||
if self._obj:
|
||||
obj = obj.pool.get(self._obj)
|
||||
obj_names = {}
|
||||
for obj_id, obj_name in obj.name_get(cursor, user,
|
||||
[x for x in res.values() if x], context=context):
|
||||
obj_names[obj_id] = obj_name
|
||||
for i in ids:
|
||||
if res.get(i) and res[i] in obj_names:
|
||||
res[i] = (res[i], obj_names[res[i]])
|
||||
else:
|
||||
res[i] = False
|
||||
return res
|
||||
|
||||
def __init__(self, **args):
|
||||
super(Property, self).__init__('', None, self._fnct_write, None, **args)
|
||||
|
||||
def get(self, cursor, obj, ids, name, user=None, offset=0, context=None,
|
||||
values=None):
|
||||
return self._fnct_read(obj, cursor, user, ids, name, self._arg,
|
||||
context=context)
|
||||
|
||||
def set(self, cursor, obj, obj_id, name, value, user=None, context=None):
|
||||
self._fnct_write(obj, cursor, user, obj_id, name, value,
|
||||
self._obj, context=context)
|
||||
|
||||
_TYPE2CLASS = {
|
||||
}
|
||||
|
||||
for klass in (Boolean, Integer, BigInteger, Reference, Char, Sha, Text, Float,
|
||||
Numeric, Date, DateTime, Time, Binary, Selection, Many2One, One2Many,
|
||||
Many2Many):
|
||||
_TYPE2CLASS[klass._type] = klass
|
||||
from trytond.model.fields import *
|
||||
+6
-3
@@ -12,6 +12,7 @@ import version
|
||||
from config import CONFIG
|
||||
import logging
|
||||
from trytond.security import Session
|
||||
from trytond.backend.postgresql import *
|
||||
|
||||
RE_FROM = re.compile('.* from "?([a-zA-Z_0-9]+)"?.*$')
|
||||
RE_INTO = re.compile('.* into "?([a-zA-Z_0-9]+)"?.*$')
|
||||
@@ -410,9 +411,11 @@ class table_handler:
|
||||
rtable = table_handler(
|
||||
self.cursor, relation_table, object_name=None,
|
||||
module_name= self.module_name)
|
||||
from osv.fields import Integer
|
||||
rtable.add_raw_column(rtable_from, ('int4', 'int4'), Integer._symbol_set)
|
||||
rtable.add_raw_column(rtable_to, ('int4', 'int4'), Integer._symbol_set)
|
||||
integer = FIELDS['integer']
|
||||
rtable.add_raw_column(rtable_from, integer.sql_type(None),
|
||||
(integer.symbol_c, integer.symbol_f))
|
||||
rtable.add_raw_column(rtable_to, integer.sql_type(None),
|
||||
(integer.symbol_c, integer.symbol_f))
|
||||
rtable.add_fk(rtable_from, self.table_name, on_delete=on_delete_from)
|
||||
rtable.add_fk(rtable_to, other_table, on_delete=on_delete_to)
|
||||
rtable.not_null_action(rtable_from)
|
||||
|
||||
@@ -5,7 +5,6 @@ try:
|
||||
import cStringIO as StringIO
|
||||
except ImportError:
|
||||
import StringIO
|
||||
from trytond.osv.fields import Integer
|
||||
import os.path
|
||||
from trytond.netsvc import LocalService
|
||||
from trytond.config import CONFIG
|
||||
@@ -194,7 +193,7 @@ class RecordTagHandler:
|
||||
eval_attr = attributes.get('eval', '')
|
||||
|
||||
if search_attr:
|
||||
search_model = self.model._columns[field_name]._obj
|
||||
search_model = self.model._columns[field_name].model_name
|
||||
f_obj = self.mh.pool.get(search_model)
|
||||
answer = f_obj.browse(
|
||||
self.mh.cursor, self.mh.user,
|
||||
|
||||
Reference in new issue
Block a user