[MERGE] osv_memory removed, merged into database-backed Model/TransientModel
bzr revid: odo@openerp.com-20110927213712-9aa0x0aqoh13f6ga
This commit is contained in:
commit
762637518b
|
@ -22,6 +22,8 @@
|
|||
""" OpenERP core library.
|
||||
|
||||
"""
|
||||
# The hard-coded super-user id (a.k.a. administrator, or root user).
|
||||
SUPERUSER_ID = 1
|
||||
|
||||
import addons
|
||||
import conf
|
||||
|
|
|
@ -63,7 +63,7 @@ class ir_model(osv.osv):
|
|||
models = self.browse(cr, uid, ids, context=context)
|
||||
res = dict.fromkeys(ids)
|
||||
for model in models:
|
||||
res[model.id] = isinstance(self.pool.get(model.model), osv.osv_memory)
|
||||
res[model.id] = self.pool.get(model.model).is_transient()
|
||||
return res
|
||||
|
||||
def _search_osv_memory(self, cr, uid, model, name, domain, context=None):
|
||||
|
@ -165,7 +165,7 @@ class ir_model(osv.osv):
|
|||
pass
|
||||
x_custom_model._name = model
|
||||
x_custom_model._module = False
|
||||
a = x_custom_model.createInstance(self.pool, cr)
|
||||
a = x_custom_model.create_instance(self.pool, cr)
|
||||
if (not a._columns) or ('x_name' in a._columns.keys()):
|
||||
x_name = 'x_name'
|
||||
else:
|
||||
|
@ -481,14 +481,12 @@ class ir_model_access(osv.osv):
|
|||
|
||||
if isinstance(model, browse_record):
|
||||
assert model._table_name == 'ir.model', 'Invalid model object'
|
||||
model_name = model.name
|
||||
model_name = model.model
|
||||
else:
|
||||
model_name = model
|
||||
|
||||
# osv_memory objects can be read by everyone, as they only return
|
||||
# results that belong to the current user (except for superuser)
|
||||
model_obj = self.pool.get(model_name)
|
||||
if isinstance(model_obj, osv.osv_memory):
|
||||
# TransientModel records have no access rights, only an implicit access rule
|
||||
if self.pool.get(model_name).is_transient():
|
||||
return True
|
||||
|
||||
# We check if a specific rule exists
|
||||
|
@ -523,7 +521,7 @@ class ir_model_access(osv.osv):
|
|||
}
|
||||
|
||||
raise except_orm(_('AccessError'), msgs[mode] % (model_name, groups) )
|
||||
return r
|
||||
return r or False
|
||||
|
||||
__cache_clearing_methods = []
|
||||
|
||||
|
|
|
@ -26,8 +26,7 @@ from functools import partial
|
|||
import tools
|
||||
from tools.safe_eval import safe_eval as eval
|
||||
from tools.misc import unquote as unquote
|
||||
|
||||
SUPERUSER_UID = 1
|
||||
from openerp import SUPERUSER_ID
|
||||
|
||||
class ir_rule(osv.osv):
|
||||
_name = 'ir.rule'
|
||||
|
@ -68,7 +67,7 @@ class ir_rule(osv.osv):
|
|||
return res
|
||||
|
||||
def _check_model_obj(self, cr, uid, ids, context=None):
|
||||
return not any(isinstance(self.pool.get(rule.model_id.model), osv.osv_memory) for rule in self.browse(cr, uid, ids, context))
|
||||
return not any(self.pool.get(rule.model_id.model).is_transient() for rule in self.browse(cr, uid, ids, context))
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Name', size=128, select=1),
|
||||
|
@ -104,7 +103,7 @@ class ir_rule(osv.osv):
|
|||
if mode not in self._MODES:
|
||||
raise ValueError('Invalid mode: %r' % (mode,))
|
||||
|
||||
if uid == SUPERUSER_UID:
|
||||
if uid == SUPERUSER_ID:
|
||||
return None
|
||||
cr.execute("""SELECT r.id
|
||||
FROM ir_rule r
|
||||
|
@ -117,10 +116,10 @@ class ir_rule(osv.osv):
|
|||
rule_ids = [x[0] for x in cr.fetchall()]
|
||||
if rule_ids:
|
||||
# browse user as super-admin root to avoid access errors!
|
||||
user = self.pool.get('res.users').browse(cr, SUPERUSER_UID, uid)
|
||||
user = self.pool.get('res.users').browse(cr, SUPERUSER_ID, uid)
|
||||
global_domains = [] # list of domains
|
||||
group_domains = {} # map: group -> list of domains
|
||||
for rule in self.browse(cr, SUPERUSER_UID, rule_ids):
|
||||
for rule in self.browse(cr, SUPERUSER_ID, rule_ids):
|
||||
# read 'domain' as UID to have the correct eval context for the rule.
|
||||
rule_domain = self.read(cr, uid, rule.id, ['domain'])['domain']
|
||||
dom = expression.normalize(rule_domain)
|
||||
|
|
|
@ -19,18 +19,15 @@
|
|||
#
|
||||
##############################################################################
|
||||
|
||||
from osv import osv
|
||||
from osv.orm import orm_memory
|
||||
import openerp
|
||||
|
||||
class osv_memory_autovacuum(osv.osv_memory):
|
||||
class osv_memory_autovacuum(openerp.osv.osv.osv_memory):
|
||||
""" Expose the osv_memory.vacuum() method to the cron jobs mechanism. """
|
||||
_name = 'osv_memory.autovacuum'
|
||||
|
||||
def power_on(self, cr, uid, context=None):
|
||||
for model in self.pool.obj_list():
|
||||
obj = self.pool.get(model)
|
||||
if isinstance(obj, orm_memory):
|
||||
obj.vaccum(cr, uid)
|
||||
for model in self.pool.models.values():
|
||||
if model.is_transient():
|
||||
model._transient_vacuum(cr, uid)
|
||||
return True
|
||||
|
||||
osv_memory_autovacuum()
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ class res_currency(osv.osv):
|
|||
(name, (COALESCE(company_id,-1)))""")
|
||||
|
||||
def read(self, cr, user, ids, fields=None, context=None, load='_classic_read'):
|
||||
res = super(osv.osv, self).read(cr, user, ids, fields, context, load)
|
||||
res = super(res_currency, self).read(cr, user, ids, fields, context, load)
|
||||
currency_rate_obj = self.pool.get('res.currency.rate')
|
||||
for r in res:
|
||||
if r.__contains__('rate_ids'):
|
||||
|
|
|
@ -144,45 +144,3 @@
|
|||
!python {model: res.partner.category}: |
|
||||
self.pool._init = True
|
||||
|
||||
-
|
||||
"OSV Memory: Verify that osv_memory properly handles large data allocation"
|
||||
-
|
||||
1. No "count-based" auto-vaccuum when max_count is disabled
|
||||
-
|
||||
!python {model: base.language.export}: |
|
||||
# setup special limits for the test, these will be reset at next pool reload anyway
|
||||
self._max_count = None
|
||||
num_recs = 250
|
||||
for i in xrange(num_recs):
|
||||
self.create(cr, uid, {'format':'po'})
|
||||
assert (len(self.datas) >= num_recs), "OSV Memory must not auto-vaccum records from the current transaction if max_count is not set"
|
||||
-
|
||||
2. Auto-vaccuum should be enabled when max_count is set
|
||||
-
|
||||
!python {model: base.language.export}: |
|
||||
# setup special limits for the test, these will be reset at next pool reload anyway
|
||||
self._max_count = 100
|
||||
num_recs = 219
|
||||
for i in xrange(num_recs):
|
||||
self.create(cr, uid, {'name': i, 'format':'po'})
|
||||
assert (self._max_count <= len(self.datas) < self._max_count + self._check_time), "OSV Memory must auto-expire records when max_count is reached"
|
||||
for k,v in self.datas.iteritems():
|
||||
assert (int(v['name']) >= (num_recs - (self._max_count + self._check_time))), "OSV Memory must auto-expire records based on age"
|
||||
-
|
||||
3. Auto-vaccuum should be based on age only when max_count is not set
|
||||
-
|
||||
!python {model: base.language.export}: |
|
||||
# setup special limits for the test, these will be reset at next pool reload anyway
|
||||
self._max_count = None
|
||||
self._max_hours = 0.01 #36 seconds
|
||||
num_recs = 200
|
||||
for i in xrange(num_recs):
|
||||
self.create(cr, uid, {'format':'po'})
|
||||
assert (len(self.datas) >= num_recs), "OSV Memory must not auto-expire records from the current transaction"
|
||||
|
||||
# expire all records
|
||||
for k,v in self.datas.iteritems():
|
||||
v['internal.date_access'] = 0
|
||||
self.vaccum(cr, 1, force=True)
|
||||
|
||||
assert (len(self.datas) == 0), "OSV Memory must expire old records after vaccuum"
|
||||
|
|
|
@ -339,16 +339,16 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
|||
cr.execute("""select model,name from ir_model where id NOT IN (select distinct model_id from ir_model_access)""")
|
||||
for (model, name) in cr.fetchall():
|
||||
model_obj = pool.get(model)
|
||||
if model_obj and not isinstance(model_obj, osv.osv.osv_memory):
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, 'object %s (%s) has no access rules!' % (model, name))
|
||||
if model_obj and not model_obj.is_transient():
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, 'Model %s (%s) has no access rules!' % (model, name))
|
||||
|
||||
# Temporary warning while we remove access rights on osv_memory objects, as they have
|
||||
# been replaced by owner-only access rights
|
||||
cr.execute("""select distinct mod.model, mod.name from ir_model_access acc, ir_model mod where acc.model_id = mod.id""")
|
||||
for (model, name) in cr.fetchall():
|
||||
model_obj = pool.get(model)
|
||||
if isinstance(model_obj, osv.osv.osv_memory) and not isinstance(model_obj, osv.osv.osv):
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, 'In-memory object %s (%s) should not have explicit access rules!' % (model, name))
|
||||
if model_obj and model_obj.is_transient():
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, 'The transient model %s (%s) should not have explicit access rules!' % (model, name))
|
||||
|
||||
cr.execute("SELECT model from ir_model")
|
||||
for (model,) in cr.fetchall():
|
||||
|
@ -356,7 +356,7 @@ def load_modules(db, force_demo=False, status=None, update_module=False):
|
|||
if obj:
|
||||
obj._check_removed_columns(cr, log=True)
|
||||
else:
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, "Model %s is referenced but not present in the orm pool!" % model)
|
||||
logger.notifyChannel('init', netsvc.LOG_WARNING, "Model %s is declared but cannot be loaded! (Perhaps a module was partially removed or renamed)" % model)
|
||||
|
||||
# Cleanup orphan records
|
||||
pool.get('ir.model.data')._process_end(cr, 1, processed_modules)
|
||||
|
|
|
@ -277,7 +277,6 @@ def init_module_models(cr, module_name, obj_list):
|
|||
TODO better explanation of _auto_init and init.
|
||||
|
||||
"""
|
||||
|
||||
logger.notifyChannel('init', netsvc.LOG_INFO,
|
||||
'module %s: creating or updating database tables' % module_name)
|
||||
todo = []
|
||||
|
|
|
@ -89,10 +89,10 @@ class Registry(object):
|
|||
|
||||
res = []
|
||||
|
||||
# Instantiate registered classes (via metamodel discovery or via explicit
|
||||
# constructor call), and add them to the pool.
|
||||
# Instantiate registered classes (via the MetaModel automatic discovery
|
||||
# or via explicit constructor call), and add them to the pool.
|
||||
for cls in openerp.osv.orm.MetaModel.module_to_models.get(module.name, []):
|
||||
res.append(cls.createInstance(self, cr))
|
||||
res.append(cls.create_instance(self, cr))
|
||||
|
||||
return res
|
||||
|
||||
|
|
|
@ -450,7 +450,7 @@ class expression(object):
|
|||
# field could not be found in model columns, it's probably invalid, unless
|
||||
# it's one of the _log_access special fields
|
||||
# TODO: make these fields explicitly available in self.columns instead!
|
||||
if (field_path[0] not in MAGIC_COLUMNS) and (left not in MAGIC_COLUMNS):
|
||||
if field_path[0] not in MAGIC_COLUMNS:
|
||||
raise ValueError("Invalid field %r in domain expression %r" % (left, exp))
|
||||
continue
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ class _column(object):
|
|||
_symbol_set = (_symbol_c, _symbol_f)
|
||||
_symbol_get = None
|
||||
|
||||
def __init__(self, string='unknown', required=False, readonly=False, domain=None, context=None, states=None, priority=0, change_default=False, size=None, ondelete="set null", translate=False, select=False, manual=False, **args):
|
||||
def __init__(self, string='unknown', required=False, readonly=False, domain=None, context=None, states=None, priority=0, change_default=False, size=None, ondelete=None, translate=False, select=False, manual=False, **args):
|
||||
"""
|
||||
|
||||
The 'manual' keyword argument specifies if the field is a custom one.
|
||||
|
@ -91,7 +91,7 @@ class _column(object):
|
|||
self.help = args.get('help', '')
|
||||
self.priority = priority
|
||||
self.change_default = change_default
|
||||
self.ondelete = ondelete
|
||||
self.ondelete = ondelete.lower() if ondelete else None # defaults to 'set null' in ORM
|
||||
self.translate = translate
|
||||
self._domain = domain
|
||||
self._context = context
|
||||
|
@ -112,12 +112,6 @@ class _column(object):
|
|||
def set(self, cr, obj, id, name, value, user=None, context=None):
|
||||
cr.execute('update '+obj._table+' set '+name+'='+self._symbol_set[0]+' where id=%s', (self._symbol_set[1](value), id))
|
||||
|
||||
def set_memory(self, cr, obj, id, name, value, user=None, context=None):
|
||||
raise Exception(_('Not implemented set_memory method !'))
|
||||
|
||||
def get_memory(self, cr, obj, ids, name, user=None, context=None, values=None):
|
||||
raise Exception(_('Not implemented get_memory method !'))
|
||||
|
||||
def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
|
||||
raise Exception(_('undefined get method !'))
|
||||
|
||||
|
@ -126,9 +120,6 @@ class _column(object):
|
|||
res = obj.read(cr, uid, ids, [name], context=context)
|
||||
return [x[name] for x in res]
|
||||
|
||||
def search_memory(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, context=None):
|
||||
raise Exception(_('Not implemented search_memory method !'))
|
||||
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Simple fields
|
||||
|
@ -269,7 +260,7 @@ class binary(_column):
|
|||
_column.__init__(self, string=string, **args)
|
||||
self.filters = filters
|
||||
|
||||
def get_memory(self, cr, obj, ids, name, user=None, context=None, values=None):
|
||||
def get(self, cr, obj, ids, name, user=None, context=None, values=None):
|
||||
if not context:
|
||||
context = {}
|
||||
if not values:
|
||||
|
@ -293,9 +284,6 @@ class binary(_column):
|
|||
res[i] = val
|
||||
return res
|
||||
|
||||
get = get_memory
|
||||
|
||||
|
||||
class selection(_column):
|
||||
_type = 'selection'
|
||||
|
||||
|
@ -355,30 +343,6 @@ class many2one(_column):
|
|||
_column.__init__(self, string=string, **args)
|
||||
self._obj = obj
|
||||
|
||||
def set_memory(self, cr, obj, id, field, values, user=None, context=None):
|
||||
obj.datas.setdefault(id, {})
|
||||
obj.datas[id][field] = values
|
||||
|
||||
def get_memory(self, cr, obj, ids, name, user=None, context=None, values=None):
|
||||
result = {}
|
||||
for id in ids:
|
||||
result[id] = obj.datas[id].get(name, False)
|
||||
|
||||
# build a dictionary of the form {'id_of_distant_resource': name_of_distant_resource}
|
||||
# we use uid=1 because the visibility of a many2one field value (just id and name)
|
||||
# must be the access right of the parent form and not the linked object itself.
|
||||
obj = obj.pool.get(self._obj)
|
||||
records = dict(obj.name_get(cr, 1,
|
||||
list(set([x for x in result.values() if x and isinstance(x, (int,long))])),
|
||||
context=context))
|
||||
for id in ids:
|
||||
if result[id] in records:
|
||||
result[id] = (result[id], records[result[id]])
|
||||
else:
|
||||
result[id] = False
|
||||
|
||||
return result
|
||||
|
||||
def get(self, cr, obj, ids, name, user=None, context=None, values=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
@ -447,55 +411,6 @@ class one2many(_column):
|
|||
#one2many can't be used as condition for defaults
|
||||
assert(self.change_default != True)
|
||||
|
||||
def get_memory(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
if self._context:
|
||||
context = context.copy()
|
||||
context.update(self._context)
|
||||
if not values:
|
||||
values = {}
|
||||
res = {}
|
||||
for id in ids:
|
||||
res[id] = []
|
||||
ids2 = obj.pool.get(self._obj).search(cr, user, [(self._fields_id, 'in', ids)], limit=self._limit, context=context)
|
||||
for r in obj.pool.get(self._obj).read(cr, user, ids2, [self._fields_id], context=context, load='_classic_write'):
|
||||
if r[self._fields_id] in res:
|
||||
res[r[self._fields_id]].append(r['id'])
|
||||
return res
|
||||
|
||||
def set_memory(self, cr, obj, id, field, values, user=None, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
if self._context:
|
||||
context = context.copy()
|
||||
context.update(self._context)
|
||||
if not values:
|
||||
return
|
||||
obj = obj.pool.get(self._obj)
|
||||
for act in values:
|
||||
if act[0] == 0:
|
||||
act[2][self._fields_id] = id
|
||||
obj.create(cr, user, act[2], context=context)
|
||||
elif act[0] == 1:
|
||||
obj.write(cr, user, [act[1]], act[2], context=context)
|
||||
elif act[0] == 2:
|
||||
obj.unlink(cr, user, [act[1]], context=context)
|
||||
elif act[0] == 3:
|
||||
obj.datas[act[1]][self._fields_id] = False
|
||||
elif act[0] == 4:
|
||||
obj.datas[act[1]][self._fields_id] = id
|
||||
elif act[0] == 5:
|
||||
for o in obj.datas.values():
|
||||
if o[self._fields_id] == id:
|
||||
o[self._fields_id] = False
|
||||
elif act[0] == 6:
|
||||
for id2 in (act[2] or []):
|
||||
obj.datas[id2][self._fields_id] = id
|
||||
|
||||
def search_memory(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None):
|
||||
raise _('Not Implemented')
|
||||
|
||||
def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
|
||||
if context is None:
|
||||
context = {}
|
||||
|
@ -578,14 +493,34 @@ class one2many(_column):
|
|||
# (6, ?, ids) set a list of links
|
||||
#
|
||||
class many2many(_column):
|
||||
"""Encapsulates the logic of a many-to-many bidirectional relationship, handling the
|
||||
low-level details of the intermediary relationship table transparently.
|
||||
|
||||
:param str obj: destination model
|
||||
:param str rel: optional name of the intermediary relationship table. If not specified,
|
||||
a canonical name will be derived based on the alphabetically-ordered
|
||||
model names of the source and destination (in the form: ``amodel_bmodel_rel``).
|
||||
Automatic naming is not possible when the source and destination are
|
||||
the same, for obvious ambiguity reasons.
|
||||
:param str id1: optional name for the column holding the foreign key to the current
|
||||
model in the relationship table. If not specified, a canonical name
|
||||
will be derived based on the model name (in the form: `src_model_id`).
|
||||
:param str id2: optional name for the column holding the foreign key to the destination
|
||||
model in the relationship table. If not specified, a canonical name
|
||||
will be derived based on the model name (in the form: `dest_model_id`)
|
||||
:param str string: field label
|
||||
"""
|
||||
_classic_read = False
|
||||
_classic_write = False
|
||||
_prefetch = False
|
||||
_type = 'many2many'
|
||||
def __init__(self, obj, rel, id1, id2, string='unknown', limit=None, **args):
|
||||
|
||||
def __init__(self, obj, rel=None, id1=None, id2=None, string='unknown', limit=None, **args):
|
||||
"""
|
||||
"""
|
||||
_column.__init__(self, string=string, **args)
|
||||
self._obj = obj
|
||||
if '.' in rel:
|
||||
if rel and '.' in rel:
|
||||
raise Exception(_('The second argument of the many2many field %s must be a SQL table !'\
|
||||
'You used %s, which is not a valid SQL table name.')% (string,rel))
|
||||
self._rel = rel
|
||||
|
@ -593,7 +528,30 @@ class many2many(_column):
|
|||
self._id2 = id2
|
||||
self._limit = limit
|
||||
|
||||
def get(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
|
||||
def _sql_names(self, source_model):
|
||||
"""Return the SQL names defining the structure of the m2m relationship table
|
||||
|
||||
:return: (m2m_table, local_col, dest_col) where m2m_table is the table name,
|
||||
local_col is the name of the column holding the current model's FK, and
|
||||
dest_col is the name of the column holding the destination model's FK, and
|
||||
"""
|
||||
tbl, col1, col2 = self._rel, self._id1, self._id2
|
||||
if not all((tbl, col1, col2)):
|
||||
# the default table name is based on the stable alphabetical order of tables
|
||||
dest_model = source_model.pool.get(self._obj)
|
||||
tables = tuple(sorted([source_model._table, dest_model._table]))
|
||||
if not tbl:
|
||||
assert tables[0] != tables[1], 'Implicit/Canonical naming of m2m relationship table '\
|
||||
'is not possible when source and destination models are '\
|
||||
'the same'
|
||||
tbl = '%s_%s_rel' % tables
|
||||
if not col1:
|
||||
col1 = '%s_id' % source_model._table
|
||||
if not col2:
|
||||
col2 = '%s_id' % dest_model._table
|
||||
return (tbl, col1, col2)
|
||||
|
||||
def get(self, cr, model, ids, name, user=None, offset=0, context=None, values=None):
|
||||
if not context:
|
||||
context = {}
|
||||
if not values:
|
||||
|
@ -606,7 +564,8 @@ class many2many(_column):
|
|||
if offset:
|
||||
warnings.warn("Specifying offset at a many2many.get() may produce unpredictable results.",
|
||||
DeprecationWarning, stacklevel=2)
|
||||
obj = obj.pool.get(self._obj)
|
||||
obj = model.pool.get(self._obj)
|
||||
rel, id1, id2 = self._sql_names(model)
|
||||
|
||||
# static domains are lists, and are evaluated both here and on client-side, while string
|
||||
# domains supposed by dynamic and evaluated on client-side only (thus ignored here)
|
||||
|
@ -636,11 +595,11 @@ class many2many(_column):
|
|||
%(order_by)s \
|
||||
%(limit)s \
|
||||
OFFSET %(offset)d' \
|
||||
% {'rel': self._rel,
|
||||
% {'rel': rel,
|
||||
'from_c': from_c,
|
||||
'tbl': obj._table,
|
||||
'id1': self._id1,
|
||||
'id2': self._id2,
|
||||
'id1': id1,
|
||||
'id2': id2,
|
||||
'where_c': where_c,
|
||||
'limit': limit_str,
|
||||
'order_by': order_by,
|
||||
|
@ -651,31 +610,32 @@ class many2many(_column):
|
|||
res[r[1]].append(r[0])
|
||||
return res
|
||||
|
||||
def set(self, cr, obj, id, name, values, user=None, context=None):
|
||||
def set(self, cr, model, id, name, values, user=None, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
if not values:
|
||||
return
|
||||
obj = obj.pool.get(self._obj)
|
||||
rel, id1, id2 = self._sql_names(model)
|
||||
obj = model.pool.get(self._obj)
|
||||
for act in values:
|
||||
if not (isinstance(act, list) or isinstance(act, tuple)) or not act:
|
||||
continue
|
||||
if act[0] == 0:
|
||||
idnew = obj.create(cr, user, act[2], context=context)
|
||||
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s,%s)', (id, idnew))
|
||||
cr.execute('insert into '+rel+' ('+id1+','+id2+') values (%s,%s)', (id, idnew))
|
||||
elif act[0] == 1:
|
||||
obj.write(cr, user, [act[1]], act[2], context=context)
|
||||
elif act[0] == 2:
|
||||
obj.unlink(cr, user, [act[1]], context=context)
|
||||
elif act[0] == 3:
|
||||
cr.execute('delete from '+self._rel+' where ' + self._id1 + '=%s and '+ self._id2 + '=%s', (id, act[1]))
|
||||
cr.execute('delete from '+rel+' where ' + id1 + '=%s and '+ id2 + '=%s', (id, act[1]))
|
||||
elif act[0] == 4:
|
||||
# following queries are in the same transaction - so should be relatively safe
|
||||
cr.execute('SELECT 1 FROM '+self._rel+' WHERE '+self._id1+' = %s and '+self._id2+' = %s', (id, act[1]))
|
||||
cr.execute('SELECT 1 FROM '+rel+' WHERE '+id1+' = %s and '+id2+' = %s', (id, act[1]))
|
||||
if not cr.fetchone():
|
||||
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s,%s)', (id, act[1]))
|
||||
cr.execute('insert into '+rel+' ('+id1+','+id2+') values (%s,%s)', (id, act[1]))
|
||||
elif act[0] == 5:
|
||||
cr.execute('delete from '+self._rel+' where ' + self._id1 + ' = %s', (id,))
|
||||
cr.execute('delete from '+rel+' where ' + id1 + ' = %s', (id,))
|
||||
elif act[0] == 6:
|
||||
|
||||
d1, d2,tables = obj.pool.get('ir.rule').domain_get(cr, user, obj._name, context=context)
|
||||
|
@ -683,10 +643,10 @@ class many2many(_column):
|
|||
d1 = ' and ' + ' and '.join(d1)
|
||||
else:
|
||||
d1 = ''
|
||||
cr.execute('delete from '+self._rel+' where '+self._id1+'=%s AND '+self._id2+' IN (SELECT '+self._rel+'.'+self._id2+' FROM '+self._rel+', '+','.join(tables)+' WHERE '+self._rel+'.'+self._id1+'=%s AND '+self._rel+'.'+self._id2+' = '+obj._table+'.id '+ d1 +')', [id, id]+d2)
|
||||
cr.execute('delete from '+rel+' where '+id1+'=%s AND '+id2+' IN (SELECT '+rel+'.'+id2+' FROM '+rel+', '+','.join(tables)+' WHERE '+rel+'.'+id1+'=%s AND '+rel+'.'+id2+' = '+obj._table+'.id '+ d1 +')', [id, id]+d2)
|
||||
|
||||
for act_nbr in act[2]:
|
||||
cr.execute('insert into '+self._rel+' ('+self._id1+','+self._id2+') values (%s, %s)', (id, act_nbr))
|
||||
cr.execute('insert into '+rel+' ('+id1+','+id2+') values (%s, %s)', (id, act_nbr))
|
||||
|
||||
#
|
||||
# TODO: use a name_search
|
||||
|
@ -694,32 +654,6 @@ class many2many(_column):
|
|||
def search(self, cr, obj, args, name, value, offset=0, limit=None, uid=None, operator='like', context=None):
|
||||
return obj.pool.get(self._obj).search(cr, uid, args+self._domain+[('name', operator, value)], offset, limit, context=context)
|
||||
|
||||
def get_memory(self, cr, obj, ids, name, user=None, offset=0, context=None, values=None):
|
||||
result = {}
|
||||
for id in ids:
|
||||
result[id] = obj.datas[id].get(name, [])
|
||||
return result
|
||||
|
||||
def set_memory(self, cr, obj, id, name, values, user=None, context=None):
|
||||
if not values:
|
||||
return
|
||||
for act in values:
|
||||
# TODO: use constants instead of these magic numbers
|
||||
if act[0] == 0:
|
||||
raise _('Not Implemented')
|
||||
elif act[0] == 1:
|
||||
raise _('Not Implemented')
|
||||
elif act[0] == 2:
|
||||
raise _('Not Implemented')
|
||||
elif act[0] == 3:
|
||||
raise _('Not Implemented')
|
||||
elif act[0] == 4:
|
||||
raise _('Not Implemented')
|
||||
elif act[0] == 5:
|
||||
raise _('Not Implemented')
|
||||
elif act[0] == 6:
|
||||
obj.datas[id][name] = act[2]
|
||||
|
||||
|
||||
def get_nice_size(value):
|
||||
size = 0
|
||||
|
@ -801,8 +735,8 @@ class function(_column):
|
|||
|
||||
Implements the function field.
|
||||
|
||||
:param orm_template model: model to which the field belongs (should be ``self`` for
|
||||
a model method)
|
||||
:param orm model: model to which the field belongs (should be ``self`` for
|
||||
a model method)
|
||||
:param field_name(s): name of the field to compute, or if ``multi`` is provided,
|
||||
list of field names to compute.
|
||||
:type field_name(s): str | [str]
|
||||
|
@ -865,8 +799,8 @@ class function(_column):
|
|||
|
||||
Callable that implements the ``write`` operation for the function field.
|
||||
|
||||
:param orm_template model: model to which the field belongs (should be ``self`` for
|
||||
a model method)
|
||||
:param orm model: model to which the field belongs (should be ``self`` for
|
||||
a model method)
|
||||
:param int id: the identifier of the object to write on
|
||||
:param str field_name: name of the field to set
|
||||
:param fnct_inv_arg: arbitrary value passed when declaring the function field
|
||||
|
@ -887,10 +821,10 @@ class function(_column):
|
|||
a search criterion based on the function field into a new domain based only on
|
||||
columns that are stored in the database.
|
||||
|
||||
:param orm_template model: model to which the field belongs (should be ``self`` for
|
||||
a model method)
|
||||
:param orm_template model_again: same value as ``model`` (seriously! this is for backwards
|
||||
compatibility)
|
||||
:param orm model: model to which the field belongs (should be ``self`` for
|
||||
a model method)
|
||||
:param orm model_again: same value as ``model`` (seriously! this is for backwards
|
||||
compatibility)
|
||||
:param str field_name: name of the field to search on
|
||||
:param list criterion: domain component specifying the search criterion on the field.
|
||||
:rtype: list
|
||||
|
@ -935,7 +869,7 @@ class function(_column):
|
|||
corresponding records in the source model (whose field values
|
||||
need to be recomputed).
|
||||
|
||||
:param orm_template model: trigger_model
|
||||
:param orm model: trigger_model
|
||||
:param list trigger_ids: ids of the records of trigger_model that were
|
||||
modified
|
||||
:rtype: list
|
||||
|
@ -1064,14 +998,11 @@ class function(_column):
|
|||
result[id] = self.postprocess(cr, uid, obj, name, result[id], context)
|
||||
return result
|
||||
|
||||
get_memory = get
|
||||
|
||||
def set(self, cr, obj, id, name, value, user=None, context=None):
|
||||
if not context:
|
||||
context = {}
|
||||
if self._fnct_inv:
|
||||
self._fnct_inv(obj, cr, user, id, name, value, self._fnct_inv_arg, context)
|
||||
set_memory = set
|
||||
|
||||
# ---------------------------------------------------------
|
||||
# Related fields
|
||||
|
|
1015
openerp/osv/orm.py
1015
openerp/osv/orm.py
File diff suppressed because it is too large
Load Diff
|
@ -21,16 +21,17 @@
|
|||
|
||||
#.apidoc title: Objects Services (OSV)
|
||||
|
||||
import logging
|
||||
from psycopg2 import IntegrityError, errorcodes
|
||||
|
||||
import orm
|
||||
import openerp
|
||||
import openerp.netsvc as netsvc
|
||||
import openerp.pooler as pooler
|
||||
import openerp.sql_db as sql_db
|
||||
import logging
|
||||
from psycopg2 import IntegrityError, errorcodes
|
||||
from openerp.tools.func import wraps
|
||||
from openerp.tools.translate import translate
|
||||
from openerp.osv.orm import MetaModel
|
||||
|
||||
from openerp.osv.orm import MetaModel, Model, TransientModel, AbstractModel
|
||||
|
||||
class except_osv(Exception):
|
||||
def __init__(self, name, value, exc_type='warning'):
|
||||
|
@ -198,17 +199,10 @@ class object_proxy():
|
|||
cr.close()
|
||||
return res
|
||||
|
||||
|
||||
class osv_memory(orm.orm_memory):
|
||||
""" Deprecated class. """
|
||||
__metaclass__ = MetaModel
|
||||
_register = False # Set to false if the model shouldn't be automatically discovered.
|
||||
|
||||
|
||||
class osv(orm.orm):
|
||||
""" Deprecated class. """
|
||||
__metaclass__ = MetaModel
|
||||
_register = False # Set to false if the model shouldn't be automatically discovered.
|
||||
# deprecated - for backward compatibility.
|
||||
osv = Model
|
||||
osv_memory = TransientModel
|
||||
osv_abstract = AbstractModel # ;-)
|
||||
|
||||
|
||||
def start_object_proxy():
|
||||
|
|
|
@ -307,7 +307,7 @@ class YamlInterpreter(object):
|
|||
import openerp.osv as osv
|
||||
record, fields = node.items()[0]
|
||||
model = self.get_model(record.model)
|
||||
if isinstance(model, osv.osv.osv_memory):
|
||||
if model.is_transient():
|
||||
record_dict=self.create_osv_memory_record(record, fields)
|
||||
else:
|
||||
self.validate_xml_id(record.id)
|
||||
|
|
Loading…
Reference in New Issue