diff --git a/CHANGELOG b/CHANGELOG
index 7f070648f4..258d7bb793 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,4 @@
+* Remove _inherits
* Add dynamic label
* Add prefix, suffix on tree view
* Replace _constraints with validate in ModelStorage
diff --git a/doc/ref/models/models.rst b/doc/ref/models/models.rst
index eb67101b2d..37cdb8d170 100644
--- a/doc/ref/models/models.rst
+++ b/doc/ref/models/models.rst
@@ -17,17 +17,6 @@ Class attributes are:
It contains the a unique name to reference the model throughout the
platform.
-.. attribute:: Model._inherits
-
- It contains a dictionary with one or more :attr:`Model._name` as keys. For each
- key a :class:`~trytond.model.fields.Many2One` field is defined as value. The
- :class:`trytond.model.fields.Many2One` fields must be defined in the the current
- model fields. A referenced model with ``_inherits`` is a generalization_ of the
- current model which is *specialized*. In the specialized model it is possible to
- interact with all attributes and methods of the general model.
-
- .. _generalization: http://en.wikipedia.org/wiki/Class_diagram#Generalization
-
.. attribute:: Model.__rpc__
It contains a dictionary with method name as key and an instance of
diff --git a/trytond/convert.py b/trytond/convert.py
index 3c4d3b4eeb..852a252571 100644
--- a/trytond/convert.py
+++ b/trytond/convert.py
@@ -340,7 +340,6 @@ class Fs2bdAccessor:
self.fs2db[module] = {}
module_data_ids = self.ModelData.search([
('module', '=', module),
- ('inherit', '=', None),
], order=[('db_id', 'ASC')])
record_ids = {}
@@ -485,10 +484,7 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
"""
Model = record.__class__
# search the field type in the object or in a parent
- if key in Model._fields:
- field_type = Model._fields[key]._type
- else:
- field_type = Model._inherit_fields[key][2]._type
+ field_type = Model._fields[key]._type
# handle the value regarding to the type
if field_type == 'many2one':
@@ -520,7 +516,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
# problem when the corresponding recordds will be deleted:
module_data = self.ModelData.search([
('module', '=', self.module),
- ('inherit', '=', None),
], order=[('id', 'DESC')])
return set(rec.fs_id for rec in module_data)
@@ -558,8 +553,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
db_id, db_model, mdata_id, old_values = [
self.fs2db.get(module, fs_id)[x]
for x in ["db_id", "model", "id", "values"]]
- inherit_db_ids = {}
- inherit_mdata_ids = []
if not old_values:
old_values = {}
@@ -592,31 +585,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
record = self.fs2db.get_browserecord(
module, Model.__name__, record.id)
- for table, field_name, field in \
- Model._inherit_fields.values():
- inherit_db_ids[table] = getattr(record, field_name).id
-
- for table in inherit_db_ids.keys():
- data = self.ModelData.search([
- ('fs_id', '=', fs_id),
- ('module', '=', module),
- ('model', '=', table),
- ], limit=1)
- if data:
- self.ModelData.write(data, {
- 'db_id': inherit_db_ids[table],
- 'inherit': True,
- })
- data, = data
- else:
- data, = self.ModelData.create([{
- 'fs_id': fs_id,
- 'module': module,
- 'model': table,
- 'db_id': inherit_db_ids[table],
- 'inherit': True,
- }])
- inherit_mdata_ids.append((table, data.id))
data = self.ModelData.search([
('fs_id', '=', fs_id),
@@ -643,22 +611,13 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
# we cannot update a field if it was changed by a user...
if key not in old_values:
- if key in Model._fields:
- expected_value = Model._defaults.get(
- key, lambda *a: None)()
- else:
- Inherit = self.pool.get(
- Model._inherit_fields[key][0])
- expected_value = Inherit._defaults.get(
- key, lambda *a: None)()
+ expected_value = Model._defaults.get(key,
+ lambda *a: None)()
else:
expected_value = old_values[key]
# Migration from 2.0: Reference field change value
- if key in Model._fields:
- field_type = Model._fields[key]._type
- else:
- field_type = Model._inherit_fields[key][2]._type
+ field_type = Model._fields[key]._type
if field_type == 'reference':
if (expected_value and expected_value.endswith(',0')
and not db_field):
@@ -688,19 +647,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
self.fs2db.reset_browsercord(
module, Model.__name__, [record.id])
- if not inherit_db_ids:
- for table, field_name, field in \
- Model._inherit_fields.values():
- inherit_db_ids[table] = getattr(record, field_name).id
- if not inherit_mdata_ids:
- for table in inherit_db_ids.keys():
- data, = self.ModelData.search([
- ('fs_id', '=', fs_id),
- ('module', '=', module),
- ('model', '=', table),
- ], limit=1)
- inherit_mdata_ids.append((table, data.id))
-
if to_update:
# re-read it: this ensure that we store the real value
# in the model_data table:
@@ -725,16 +671,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
'values': str(values),
'date_update': datetime.datetime.now(),
})
- for table, inherit_mdata_id in inherit_mdata_ids:
- self.ModelData.write(
- [self.ModelData(inherit_mdata_id)], {
- 'fs_id': fs_id,
- 'model': table,
- 'module': module,
- 'db_id': inherit_db_ids[table],
- 'values': str(values),
- 'date_update': datetime.datetime.now(),
- })
# reset_browsercord to keep cache memory low
self.fs2db.reset_browsercord(module, Model.__name__, [record.id])
@@ -742,11 +678,6 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
# this record is new, create it in the db:
with Transaction().set_context(module=module, language='en_US'):
record, = Model.create([values])
- inherit_db_ids = {}
-
- for table, field_name, field in (
- Model._inherit_fields.values()):
- inherit_db_ids[table] = getattr(record, field_name).id
# re-read it: this ensure that we store the real value
# in the model_data table:
@@ -754,25 +685,14 @@ class TrytondXmlHandler(sax.handler.ContentHandler):
for key in values:
values[key] = self._clean_value(key, record)
- to_create = [{
- 'fs_id': fs_id,
- 'model': model,
- 'module': module,
- 'db_id': record.id,
- 'values': str(values),
- 'noupdate': self.noupdate,
- }]
- for table in inherit_db_ids.keys():
- to_create.append({
- 'fs_id': fs_id,
- 'model': table,
- 'module': module,
- 'db_id': inherit_db_ids[table],
- 'values': str(values),
- 'inherit': True,
- 'noupdate': self.noupdate,
- })
- mdata = self.ModelData.create(to_create)[0]
+ mdata, = self.ModelData.create([{
+ 'fs_id': fs_id,
+ 'model': model,
+ 'module': module,
+ 'db_id': record.id,
+ 'values': str(values),
+ 'noupdate': self.noupdate,
+ }])
# update fs2db:
self.fs2db.set(module, fs_id, {
diff --git a/trytond/ir/action.py b/trytond/ir/action.py
index e14c88930d..0e213d9ac8 100644
--- a/trytond/ir/action.py
+++ b/trytond/ir/action.py
@@ -4,8 +4,9 @@ import base64
import os
from operator import itemgetter
from collections import defaultdict
+from functools import partial
-from ..model import ModelView, ModelSQL, fields
+from ..model import ModelView, ModelStorage, ModelSQL, fields
from ..tools import file_open, safe_eval
from ..backend import TableHandler
from ..pyson import PYSONEncoder, CONTEXT, PYSON
@@ -82,7 +83,7 @@ class Action(ModelSQL, ModelView):
@classmethod
def get_action_values(cls, type_, action_ids):
Action = Pool().get(type_)
- columns = set(Action._fields.keys() + Action._inherit_fields.keys())
+ columns = set(Action._fields.keys())
columns.add('icon.rec_name')
to_remove = ()
if type_ == 'ir.action.report':
@@ -230,10 +231,125 @@ class ActionKeyword(ModelSQL, ModelView):
return keywords
-class ActionReport(ModelSQL, ModelView):
+class ActionMixin(ModelSQL):
+
+ @classmethod
+ def __setup__(cls):
+ super(ActionMixin, cls).__setup__()
+ for name in dir(Action):
+ field = getattr(Action, name)
+ if (isinstance(field, fields.Field)
+ and not getattr(cls, name, None)):
+ setattr(cls, name, fields.Function(field, 'get_action',
+ setter='set_action', searcher='search_action'))
+ default_func = 'default_' + name
+ if getattr(Action, default_func, None):
+ setattr(cls, default_func,
+ partial(ActionMixin.default_action, name))
+
+ @staticmethod
+ def default_action(name):
+ pool = Pool()
+ Action = pool.get('ir.action')
+ return getattr(Action, 'default_' + name, None)()
+
+ @classmethod
+ def get_action(cls, ids, names):
+ records = cls.browse(ids)
+ result = {}
+ for name in names:
+ result[name] = values = {}
+ for record in records:
+ value = getattr(record, 'action')
+ convert = lambda v: v
+ if value is not None:
+ value = getattr(value, name)
+ if isinstance(value, ModelStorage):
+ if cls._fields[name]._type == 'reference':
+ convert = str
+ else:
+ convert = int
+ elif isinstance(value, (list, tuple)):
+ convert = lambda v: [r.id for r in v]
+ values[record.id] = convert(value)
+ return result
+
+ @classmethod
+ def set_action(cls, records, name, value):
+ pool = Pool()
+ Action = pool.get('ir.action')
+ Action.write([r.action for r in records], {
+ name: value,
+ })
+
+ @classmethod
+ def search_action(cls, name, clause):
+ return [('action.' + name,) + tuple(clause[1:])]
+
+ @classmethod
+ def create(cls, vlist):
+ pool = Pool()
+ Action = pool.get('ir.action')
+ new_records = []
+ for values in vlist:
+ later = {}
+ action_values = {}
+ values = values.copy()
+ for field in values:
+ if field in Action._fields:
+ action_values[field] = values[field]
+ if hasattr(getattr(cls, field), 'set'):
+ later[field] = values[field]
+ for field in later:
+ del values[field]
+ action_values['type'] = cls.default_type()
+ cursor = Transaction().cursor
+ if cursor.nextid(cls._table):
+ cursor.setnextid(cls._table, cursor.currid(Action._table))
+ action, = Action.create([action_values])
+ values['action'] = action.id
+ record, = super(ActionMixin, cls).create([values])
+ cursor.execute('UPDATE "' + cls._table + '" SET id = %s '
+ 'WHERE id = %s', (action.id, record.id))
+ cursor.update_auto_increment(cls._table, action.id)
+ record = cls(action.id)
+ new_records.append(record)
+ cls.write([record], later)
+ return new_records
+
+ @classmethod
+ def write(cls, records, values):
+ pool = Pool()
+ ActionKeyword = pool.get('ir.action.keyword')
+ super(ActionMixin, cls).write(records, values)
+ ActionKeyword._get_keyword_cache.clear()
+
+ @classmethod
+ def delete(cls, records):
+ pool = Pool()
+ Action = pool.get('ir.action')
+ actions = [x.action for x in records]
+ super(ActionMixin, cls).delete(records)
+ Action.delete(actions)
+
+ @classmethod
+ def copy(cls, records, default=None):
+ pool = Pool()
+ Action = pool.get('ir.action')
+ if default is None:
+ default = {}
+ default = default.copy()
+ new_records = []
+ for record in records:
+ default['action'] = Action.copy([record.action])[0].id
+ new_records.extend(super(ActionMixin, cls).copy([record],
+ default=default))
+ return new_records
+
+
+class ActionReport(ActionMixin, ModelSQL, ModelView):
"Action report"
__name__ = 'ir.action.report'
- _inherits = {'ir.action': 'action'}
model = fields.Char('Model')
report_name = fields.Char('Internal Name', required=True)
report = fields.Char('Path')
@@ -499,8 +615,6 @@ class ActionReport(ModelSQL, ModelView):
@classmethod
def copy(cls, reports, default=None):
- Action = Pool().get('ir.action')
-
if default is None:
default = {}
default = default.copy()
@@ -511,62 +625,23 @@ class ActionReport(ModelSQL, ModelView):
if report.report:
default['report_content'] = None
default['report_name'] = report.report_name
- default['action'] = Action.copy([report.action])[0].id
new_reports.extend(super(ActionReport, cls).copy([report],
default=default))
return new_reports
- @classmethod
- def create(cls, vlist):
- new_vlist = []
- for vals in vlist:
- later = {}
- vals = vals.copy()
- for field in vals:
- if (field in cls._fields
- and hasattr(cls._fields[field], 'set')):
- later[field] = vals[field]
- for field in later:
- del vals[field]
- cursor = Transaction().cursor
- if cursor.nextid(cls._table):
- cursor.setnextid(cls._table, cursor.currid('ir_action'))
- report, = super(ActionReport, cls).create([vals])
- cursor.execute('SELECT action FROM "' + cls._table + '" '
- 'WHERE id = %s', (report.id,))
- new_id, = cursor.fetchone()
- cursor.execute('UPDATE "' + cls._table + '" SET id = %s '
- 'WHERE id = %s', (new_id, report.id))
- cursor.update_auto_increment(cls._table, new_id)
- report = cls(new_id)
- new_vlist.append(report)
- cls.write([report], later)
- return new_vlist
-
@classmethod
def write(cls, reports, vals):
- pool = Pool()
context = Transaction().context
if 'module' in context:
vals = vals.copy()
vals['module'] = context['module']
super(ActionReport, cls).write(reports, vals)
- pool.get('ir.action.keyword')._get_keyword_cache.clear()
-
- @classmethod
- def delete(cls, reports):
- Action = Pool().get('ir.action')
-
- actions = [x.action for x in reports]
- super(ActionReport, cls).delete(reports)
- Action.delete(actions)
-class ActionActWindow(ModelSQL, ModelView):
+class ActionActWindow(ActionMixin, ModelSQL, ModelView):
"Action act window"
__name__ = 'ir.action.act_window'
- _inherits = {'ir.action': 'action'}
domain = fields.Char('Domain Value')
context = fields.Char('Context Value')
res_model = fields.Char('Model')
@@ -771,47 +846,6 @@ class ActionActWindow(ModelSQL, ModelView):
or defaults.get(field, 'None'), CONTEXT))
return pysons
- @classmethod
- def create(cls, vlist):
- new_vlist = []
- for vals in vlist:
- later = {}
- vals = vals.copy()
- for field in vals:
- if (field in cls._fields
- and hasattr(cls._fields[field], 'set')):
- later[field] = vals[field]
- for field in later:
- del vals[field]
- cursor = Transaction().cursor
- if cursor.nextid(cls._table):
- cursor.setnextid(cls._table, cursor.currid('ir_action'))
- act_window, = super(ActionActWindow, cls).create([vals])
- cursor.execute('SELECT action FROM "' + cls._table + '" '
- 'WHERE id = %s', (act_window.id,))
- new_id, = cursor.fetchone()
- cursor.execute('UPDATE "' + cls._table + '" SET id = %s '
- 'WHERE id = %s', (new_id, act_window.id))
- cursor.update_auto_increment(cls._table, new_id)
- act_window = cls(new_id)
- new_vlist.append(act_window)
- cls.write([act_window], later)
- return new_vlist
-
- @classmethod
- def write(cls, act_windows, values):
- pool = Pool()
- super(ActionActWindow, cls).write(act_windows, values)
- pool.get('ir.action.keyword')._get_keyword_cache.clear()
-
- @classmethod
- def delete(cls, act_windows):
- Action = Pool().get('ir.action')
-
- actions = [x.action for x in act_windows]
- super(ActionActWindow, cls).delete(act_windows)
- Action.delete(actions)
-
@classmethod
def get(cls, xml_id):
'Get values from XML id or id'
@@ -824,19 +858,6 @@ class ActionActWindow(ModelSQL, ModelView):
action_id = int(xml_id)
return Action.get_action_values(cls.__name__, [action_id])[0]
- @classmethod
- def copy(cls, actions, default=None):
- Action = Pool().get('ir.action')
- if default is None:
- default = {}
- default = default.copy()
- new_actions = []
- for act_window in actions:
- default['action'] = Action.copy([act_window.action])[0].id
- new_actions.extend(super(ActionActWindow, cls).copy([act_window],
- default=default))
- return new_actions
-
class ActionActWindowView(ModelSQL, ModelView):
"Action act window view"
@@ -901,10 +922,9 @@ class ActionActWindowDomain(ModelSQL, ModelView):
return True
-class ActionWizard(ModelSQL, ModelView):
+class ActionWizard(ActionMixin, ModelSQL, ModelView):
"Action wizard"
__name__ = 'ir.action.wizard'
- _inherits = {'ir.action': 'action'}
wiz_name = fields.Char('Wizard name', required=True)
action = fields.Many2One('ir.action', 'Action', required=True,
ondelete='CASCADE')
@@ -916,68 +936,10 @@ class ActionWizard(ModelSQL, ModelView):
def default_type():
return 'ir.action.wizard'
- @classmethod
- def create(cls, vlist):
- new_vlist = []
- for vals in vlist:
- later = {}
- vals = vals.copy()
- for field in vals:
- if (field in cls._fields
- and hasattr(cls._fields[field], 'set')):
- later[field] = vals[field]
- for field in later:
- del vals[field]
- cursor = Transaction().cursor
- if cursor.nextid(cls._table):
- cursor.setnextid(cls._table, cursor.currid('ir_action'))
- wizard, = super(ActionWizard, cls).create([vals])
- cursor.execute('SELECT action FROM "' + cls._table + '" '
- 'WHERE id = %s', (wizard.id,))
- new_id, = cursor.fetchone()
- cursor.execute('UPDATE "' + cls._table + '" SET id = %s '
- 'WHERE id = %s', (new_id, wizard.id))
- cursor.update_auto_increment(cls._table, new_id)
- wizard = cls(new_id)
- new_vlist.append(wizard)
- cls.write([wizard], later)
- return new_vlist
- @classmethod
- def write(cls, wizards, values):
- pool = Pool()
- super(ActionWizard, cls).write(wizards, values)
- pool.get('ir.action.keyword')._get_keyword_cache.clear()
-
- @classmethod
- def delete(cls, wizards):
- pool = Pool()
- Action = pool.get('ir.action')
-
- actions = [x.action for x in wizards]
-
- super(ActionWizard, cls).delete(wizards)
- Action.delete(actions)
-
- @classmethod
- def copy(cls, wizards, default=None):
- Action = Pool().get('ir.action')
-
- if default is None:
- default = {}
- default = default.copy()
- new_wizards = []
- for wizard in wizards:
- default['action'] = Action.copy([wizard.action])[0].id
- new_wizards.extend(super(ActionWizard, cls).copy([wizard],
- default=default))
- return new_wizards
-
-
-class ActionURL(ModelSQL, ModelView):
+class ActionURL(ActionMixin, ModelSQL, ModelView):
"Action URL"
__name__ = 'ir.action.url'
- _inherits = {'ir.action': 'action'}
url = fields.Char('Action Url', required=True)
action = fields.Many2One('ir.action', 'Action', required=True,
ondelete='CASCADE')
@@ -989,61 +951,3 @@ class ActionURL(ModelSQL, ModelView):
@staticmethod
def default_target():
return 'new'
-
- @classmethod
- def create(cls, vlist):
- new_vlist = []
- for vals in vlist:
- later = {}
- vals = vals.copy()
- for field in vals:
- if (field in cls._fields
- and hasattr(cls._fields[field], 'set')):
- later[field] = vals[field]
- for field in later:
- del vals[field]
- cursor = Transaction().cursor
- if cursor.nextid(cls._table):
- cursor.setnextid(cls._table, cursor.currid('ir_action'))
- url, = super(ActionURL, cls).create([vals])
- cursor.execute('SELECT action FROM "' + cls._table + '" '
- 'WHERE id = %s', (url.id,))
- new_id, = cursor.fetchone()
- cls.write([url], {}) # simulate write to clear the cache
- cursor.execute('UPDATE "' + cls._table + '" SET id = %s '
- 'WHERE id = %s', (new_id, url.id))
- cursor.update_auto_increment(cls._table, new_id)
- url = cls(new_id)
- new_vlist.append(url)
- cls.write([url], later)
- return new_vlist
-
- @classmethod
- def write(cls, urls, values):
- pool = Pool()
- super(ActionURL, cls).write(urls, values)
- pool.get('ir.action.keyword')._get_keyword_cache.clear()
-
- @classmethod
- def delete(cls, urls):
- pool = Pool()
- Action = pool.get('ir.action')
-
- actions = [x.action for x in urls]
-
- super(ActionURL, cls).delete(urls)
- Action.delete(actions)
-
- @classmethod
- def copy(cls, urls, default=None):
- Action = Pool().get('ir.action')
-
- if default is None:
- default = {}
- default = default.copy()
- new_urls = []
- for url in urls:
- default['action'] = Action.copy([url.action])[0].id
- new_urls.extend(super(ActionURL, cls).copy([url],
- default=default))
- return new_urls
diff --git a/trytond/ir/model.py b/trytond/ir/model.py
index 19b3afb4ad..6dda9235f5 100644
--- a/trytond/ir/model.py
+++ b/trytond/ir/model.py
@@ -666,7 +666,6 @@ class ModelData(ModelSQL, ModelView):
date_update = fields.DateTime('Update Date')
date_init = fields.DateTime('Init Date')
values = fields.Text('Values')
- inherit = fields.Boolean('Inherit')
noupdate = fields.Boolean('No Update')
_get_id_cache = Cache('ir_model_data.get_id', context=False)
@@ -678,14 +677,24 @@ class ModelData(ModelSQL, ModelView):
'The triple (fs_id, module, model) must be unique!'),
]
+ @classmethod
+ def __register__(cls, module_name):
+ cursor = Transaction().cursor
+
+ super(ModelData, cls).__register__(module_name)
+
+ table = TableHandler(cursor, cls, module_name)
+
+ # Migration from 2.6: remove inherit
+ if table.column_exist('inherit'):
+ cursor.execute('DELETE FROM "' + cls._table + '" '
+ 'WHERE inherit = %s', (True,))
+ table.drop_column('inherit', True)
+
@staticmethod
def default_date_init():
return datetime.datetime.now()
- @staticmethod
- def default_inherit():
- return False
-
@staticmethod
def default_noupdate():
return False
@@ -708,7 +717,6 @@ class ModelData(ModelSQL, ModelView):
data = cls.search([
('module', '=', module),
('fs_id', '=', fs_id),
- ('inherit', '=', False),
], limit=1)
if not data:
raise Exception("Reference to %s not found"
diff --git a/trytond/model/fields/many2many.py b/trytond/model/fields/many2many.py
index 5c92047c9c..954af80f22 100644
--- a/trytond/model/fields/many2many.py
+++ b/trytond/model/fields/many2many.py
@@ -75,10 +75,7 @@ class Many2Many(Field):
order = self.order
Relation = Pool().get(self.relation_name)
- if self.origin in Relation._fields:
- origin_field = Relation._fields[self.origin]
- else:
- origin_field = Relation._inherit_fields[self.origin][2]
+ origin_field = Relation._fields[self.origin]
relations = []
for i in range(0, len(ids), Transaction().cursor.IN_MAX):
@@ -116,10 +113,7 @@ class Many2Many(Field):
return
Relation = pool.get(self.relation_name)
Target = self.get_target()
- if self.origin in Relation._fields:
- origin_field = Relation._fields[self.origin]
- else:
- origin_field = Relation._inherit_fields[self.origin][2]
+ origin_field = Relation._fields[self.origin]
def search_clause(ids):
if origin_field._type == 'reference':
@@ -228,10 +222,7 @@ class Many2Many(Field):
Relation = Pool().get(self.relation_name)
if not self.target:
return Relation
- if self.target in Relation._fields:
- return Relation._fields[self.target].get_target()
- else:
- return Relation._inherit_fields[self.target][2].get_target()
+ return Relation._fields[self.target].get_target()
def __set__(self, inst, value):
Target = self.get_target()
diff --git a/trytond/model/fields/one2many.py b/trytond/model/fields/one2many.py
index 0ec20f99fa..177001b786 100644
--- a/trytond/model/fields/one2many.py
+++ b/trytond/model/fields/one2many.py
@@ -79,10 +79,7 @@ class One2Many(Field):
'''
pool = Pool()
Relation = pool.get(self.model_name)
- if self.field in Relation._fields:
- field = Relation._fields[self.field]
- else:
- field = Relation._inherit_fields[self.field][2]
+ field = Relation._fields[self.field]
res = {}
for i in ids:
res[i] = []
@@ -119,10 +116,7 @@ class One2Many(Field):
if not values:
return
Target = self.get_target()
- if self.field in Target._fields:
- field = Target._fields[self.field]
- else:
- field = Target._inherit_fields[self.field][2]
+ field = Target._fields[self.field]
def search_clause(ids):
if field._type == 'reference':
diff --git a/trytond/model/model.py b/trytond/model/model.py
index 0b2663e9c2..453a8617c7 100644
--- a/trytond/model/model.py
+++ b/trytond/model/model.py
@@ -16,33 +16,11 @@ from trytond.rpc import RPC
__all__ = ['Model']
-class ModelMeta(PoolMeta):
-
- def __getattr__(self, name):
- pool = Pool()
- for model_name, _ in self._inherits.iteritems():
- Model = pool.get(model_name)
- if isinstance(getattr(Model, name, None),
- collections.Callable):
- meth = getattr(Model, name)
- if not hasattr(meth, 'im_self') or meth.im_self:
- # Return classmethod bounded to inherited class
- return meth
- else:
- for cls in Model.__mro__:
- if name in cls.__dict__:
- # Return a method bounded to current class
- return cls.__dict__[name].__get__(None, self)
- raise AttributeError("'%s' Model has no attribute '%s'"
- % (self.__name__, name))
-
-
class Model(WarningErrorMixin, URLMixin):
"""
Define a model in Tryton.
"""
- __metaclass__ = ModelMeta
- _inherits = {}
+ __metaclass__ = PoolMeta
_rec_name = 'name'
id = fields.Integer('ID', readonly=True)
@@ -76,48 +54,21 @@ class Model(WarningErrorMixin, URLMixin):
if isinstance(getattr(cls, attr), fields.Field):
cls._fields[attr] = getattr(cls, attr)
- # Set _inherit_fields
- cls._inherit_fields = {}
- for model_name in cls._inherits:
- Model = pool.get(model_name)
- cls._inherit_fields.update(Model._inherit_fields)
- for field_name in Model._fields.keys():
- cls._inherit_fields[field_name] = (model_name,
- cls._inherits[model_name],
- Model._fields[field_name])
- for field_name in Model._inherit_fields.keys():
- cls._inherit_fields[field_name] = (model_name,
- cls._inherits[model_name],
- Model._inherit_fields[field_name][2])
- # Update models that uses this one in _inherits
- for _, Model in pool.iterobject():
- if cls.__name__ in Model._inherits:
- Model.__post_setup__()
-
# Set _defaults
cls._defaults = {}
fields_names = cls._fields.keys()
- fields_names += cls._inherit_fields.keys()
for field_name in fields_names:
default_method = getattr(cls, 'default_%s' % field_name, False)
- if not default_method and field_name in cls._inherit_fields:
- icls = pool.get(cls._inherit_fields[field_name][0])
- default_method = getattr(icls, 'default_%s' % field_name,
- False)
if isinstance(default_method, collections.Callable):
cls._defaults[field_name] = default_method
for k in cls._defaults:
- assert (k in cls._fields) or (k in cls._inherit_fields), \
+ assert k in cls._fields, \
'Default function defined in %s but field %s does not exist!' \
% (cls.__name__, k,)
# Update __rpc__
- for field_name in cls._fields.keys() + cls._inherit_fields.keys():
- if field_name in cls._fields:
- field = cls._fields[field_name]
- else:
- field = cls._inherit_fields[field_name][2]
+ for field_name, field in cls._fields.iteritems():
if isinstance(field, (fields.Selection, fields.Reference)) \
and not isinstance(field.selection, (list, tuple)) \
and field.selection not in cls.__rpc__:
@@ -364,10 +315,7 @@ class Model(WarningErrorMixin, URLMixin):
for field_name in fields_names:
if field_name in cls._defaults:
value[field_name] = cls._defaults[field_name]()
- if field_name in cls._fields:
- field = cls._fields[field_name]
- else:
- field = cls._inherit_fields[field_name][2]
+ field = cls._fields[field_name]
if (field._type == 'boolean'
and not field_name in value):
value[field_name] = False
@@ -397,8 +345,6 @@ class Model(WarningErrorMixin, URLMixin):
pool = Pool()
res = value.copy()
val = {}
- for i in cls._inherits.keys():
- val.update(pool.get(i)._default_on_change(value))
for field in value.keys():
if field in cls._fields:
if cls._fields[field].on_change:
@@ -423,9 +369,6 @@ class Model(WarningErrorMixin, URLMixin):
Translation = pool.get('ir.translation')
FieldAccess = pool.get('ir.model.field.access')
- for parent in cls._inherits:
- res.update(pool.get(parent).fields_get(fields_names))
-
#Add translation to cache
language = Transaction().language
trans_args = []
@@ -619,19 +562,6 @@ class Model(WarningErrorMixin, URLMixin):
def __getattr__(self, name):
if name == 'id':
return self.__dict__['id']
- if (name not in self._fields
- and name not in self._inherit_fields):
- # Search for method on inherits parents
- pool = Pool()
- for model_name, _ in self._inherits.iteritems():
- iModel = pool.get(model_name)
- if isinstance(getattr(iModel, name, None),
- collections.Callable):
- for cls in iModel.__mro__:
- if name in cls.__dict__:
- # Return a method bounded to current class
- return cls.__dict__[name].__get__(self,
- self.__class__)
elif self._values and name in self._values:
return self._values.get(name)
raise AttributeError("'%s' Model has no attribute '%s': %s"
@@ -641,11 +571,6 @@ class Model(WarningErrorMixin, URLMixin):
if name == 'id':
self.__dict__['id'] = value
return
- if (name not in self._fields
- and name in self._inherit_fields):
- field = self._inherit_fields[name][2]
- field.__set__(self, value)
- return
super(Model, self).__setattr__(name, value)
def __getitem__(self, name):
@@ -654,8 +579,7 @@ class Model(WarningErrorMixin, URLMixin):
return getattr(self, name)
def __contains__(self, name):
- return (name in self._fields
- or name in self._inherit_fields)
+ return name in self._fields
def __int__(self):
return int(self.id)
@@ -700,10 +624,7 @@ class Model(WarningErrorMixin, URLMixin):
values = {}
if self._values:
for fname, value in self._values.iteritems():
- if fname in self._fields:
- field = self._fields[fname]
- else:
- field = self._inherit_fields[fname][2]
+ field = self._fields[fname]
if isinstance(field, fields.Reference):
if value is not None:
value = str(value)
diff --git a/trytond/model/modelsingleton.py b/trytond/model/modelsingleton.py
index 6da16ce95e..f680832c47 100644
--- a/trytond/model/modelsingleton.py
+++ b/trytond/model/modelsingleton.py
@@ -32,8 +32,7 @@ class ModelSingleton(ModelStorage):
if not singleton:
res = cls.default_get(fields_names, with_rec_name=False)
if not fields_names:
- fields_names = (set(cls._fields.keys()
- + cls._inherit_fields.keys()))
+ fields_names = cls._fields.keys()
for field_name in fields_names:
if field_name not in res:
res[field_name] = None
diff --git a/trytond/model/modelsql.py b/trytond/model/modelsql.py
index 9f705d8523..921cada5c8 100644
--- a/trytond/model/modelsql.py
+++ b/trytond/model/modelsql.py
@@ -240,20 +240,11 @@ class ModelSQL(ModelStorage):
# Get default values
default = []
- avoid_table = []
- for (i, j) in cls._inherits.items():
- if j in values:
- avoid_table.append(i)
for i in cls._fields.keys():
if not i in values \
and i not in ('create_uid', 'create_date',
'write_uid', 'write_date'):
default.append(i)
- for i in cls._inherit_fields.keys():
- if ((not i in values)
- and (not cls._inherit_fields[i][0] in avoid_table)
- and i in cls._defaults):
- default.append(i)
if len(default):
defaults = cls.default_get(default, with_rec_name=False)
@@ -269,26 +260,6 @@ class ModelSQL(ModelStorage):
(upd0, upd1, upd2) = ('', '', [])
- # Create inherits
- tocreate = {}
- for i in cls._inherits:
- if cls._inherits[i] not in values:
- tocreate[i] = {}
-
- for i in values.keys():
- if i in cls._inherit_fields:
- (inherits, _, _) = cls._inherit_fields[i]
- if i in cls._fields:
- continue
- if inherits in tocreate:
- tocreate[inherits][i] = values[i]
- del values[i]
-
- for inherits in tocreate:
- Inherits = pool.get(inherits)
- inherits_record, = Inherits.create([tocreate[inherits]])
- values[cls._inherits[inherits]] = inherits_record.id
-
# Insert record
for fname, value in values.iteritems():
field = cls._fields[fname]
@@ -433,8 +404,7 @@ class ModelSQL(ModelStorage):
cursor = Transaction().cursor
if not fields_names:
- fields_names = list(set(cls._fields.keys()
- + cls._inherit_fields.keys()))
+ fields_names = cls._fields.keys()
if not ids:
return []
@@ -451,19 +421,15 @@ class ModelSQL(ModelStorage):
field, field_related = field_name.split('.', 1)
fields_related.setdefault(field, [])
fields_related[field].append(field_related)
- elif field_name in cls._fields:
- field = cls._fields[field_name]
else:
- field = cls._inherit_fields[field_name][2]
+ field = cls._fields[field_name]
if hasattr(field, 'datetime_field') and field.datetime_field:
datetime_fields.append(field.datetime_field)
- # all inherited fields + all non inherited fields
- fields_pre = [x for x in
- fields_names + fields_related.keys() + datetime_fields
- if ((x in cls._fields
- and not hasattr(cls._fields[x], 'set'))
- or (x == '_timestamp'))] + cls._inherits.values()
+ fields_pre = [x
+ for x in fields_names + fields_related.keys() + datetime_fields
+ if (x in cls._fields and not hasattr(cls._fields[x], 'set'))
+ or (x == '_timestamp')]
res = []
table_query = ''
@@ -546,41 +512,9 @@ class ModelSQL(ModelStorage):
for i in res:
i[field] = res_trans.get(i['id'], False) or i[field]
- for table in cls._inherits:
- field = cls._inherits[table]
- inherits_fields = list(
- set(cls._inherit_fields.keys()).intersection(
- set(fields_names + fields_related.keys() + datetime_fields)
- ).difference(set(cls._fields.keys())))
- if not inherits_fields:
- for record in res:
- if field not in fields_names + fields_related.keys() + \
- datetime_fields:
- del record[field]
- continue
- inherit_related_fields = []
- for inherit_field in inherits_fields:
- if inherit_field in fields_related:
- for field_related in fields_related[inherit_field]:
- inherit_related_fields.append(
- inherit_field + '.' + field_related)
- res2 = pool.get(table).read([x[field] for x in res],
- fields_names=inherits_fields + inherit_related_fields)
-
- res3 = {}
- for i in res2:
- res3[i['id']] = i
- del i['id']
-
- for record in res:
- record.update(res3[record[field]])
- if field not in \
- fields_names + fields_related.keys() + datetime_fields:
- del record[field]
-
ids = [x['id'] for x in res]
- # all non inherited fields for which there is a get attribute
+ # all fields for which there is a get attribute
fields_post = [x for x in
fields_names + fields_related.keys() + datetime_fields
if x in cls._fields and hasattr(cls._fields[x], 'get')]
@@ -777,22 +711,17 @@ class ModelSQL(ModelStorage):
upd0 = []
upd1 = []
upd_todo = []
- updend = []
direct = []
for field in values:
- if field in cls._fields:
- if not hasattr(cls._fields[field], 'set'):
- if ((not getattr(cls._fields[field], 'translate', False))
- or (Transaction().language
- == Config.get_language())):
- upd0.append(('"' + field + '"', '%s'))
- upd1.append(FIELDS[cls._fields[field]._type]
- .sql_format(values[field]))
- direct.append(field)
- else:
- upd_todo.append(field)
+ if not hasattr(cls._fields[field], 'set'):
+ if ((not getattr(cls._fields[field], 'translate', False))
+ or (Transaction().language == Config.get_language())):
+ upd0.append(('"' + field + '"', '%s'))
+ upd1.append(FIELDS[cls._fields[field]._type]
+ .sql_format(values[field]))
+ direct.append(field)
else:
- updend.append(field)
+ upd_todo.append(field)
upd0.append(('write_uid', '%s'))
upd0.append(('write_date', '%s'))
@@ -894,24 +823,6 @@ class ModelSQL(ModelStorage):
'FROM "' + cls._table + '" '
'WHERE id = %s', (obj_id,))
- for iname in cls._inherits:
- col = cls._inherits[iname]
- iids = []
- for i in range(0, len(ids), cursor.IN_MAX):
- sub_ids = ids[i:i + cursor.IN_MAX]
- red_sql, red_ids = reduce_ids('id', sub_ids)
- cursor.execute('SELECT DISTINCT "' + col + '" '
- 'FROM "' + cls._table + '" WHERE ' + red_sql,
- red_ids)
- iids.extend([x[0] for x in cursor.fetchall()])
-
- values2 = {}
- for val in updend:
- if cls._inherit_fields[val][0] == iname:
- values2[val] = values[val]
- IModel = pool.get(iname)
- IModel.write(IModel.browse(iids), values2)
-
cls._validate(records)
# Check for Modified Preorder Tree Traversal
@@ -1330,41 +1241,6 @@ class ModelSQL(ModelStorage):
domain = domain[:]
cursor = Transaction().cursor
- def column_get(model, field_name):
- field = model._fields.get(field_name)
- if not field:
- if not field_name in model._inherit_fields:
- raise Exception('ValidateError', 'Field "%s" doesn\'t '
- 'exist on "%s"' % (field_name, model.__name__))
- parent_model = pool.get(model._inherit_fields[field_name][0])
- field = column_get(parent_model, field_name)
- return field
-
- def get_model_for_field(model, field):
- if field in model._fields:
- return model
- else:
- parent_model = pool.get(model._inherit_fields[field][0])
- return get_model_for_field(parent_model, field)
-
- def get_inherits_join(model, field):
- if field in model._fields:
- return []
- itable = pool.get(model._inherit_fields[field][0])
- table_query = ''
- table_arg = []
- if itable.table_query():
- table_query, table_args = model.table_query()
- table_query = '(' + table_query + ') AS '
- table_join = ('LEFT JOIN ' + table_query +
- '"' + itable._table + '" ON '
- '"%s".id = "%s"."%s"'
- % (itable._table, model._table,
- model._inherits[itable.__name__]))
- inherits = [(table_join, table_arg)]
- inherits.extend(get_inherits_join(itable, field))
- return inherits
-
for arg in domain:
if arg[1] not in OPERATORS:
raise Exception('ValidateError', 'Argument "%s" not supported'
@@ -1373,21 +1249,13 @@ class ModelSQL(ModelStorage):
joins = []
while i < len(domain):
fargs = domain[i][0].split('.', 1)
- if fargs[0] in cls._inherit_fields:
- inherit_joins = get_inherits_join(cls, fargs[0])
- for (table_join, table_arg) in inherit_joins:
- if table_join not in tables:
- tables.append(table_join)
- tables_args.extend(table_arg)
-
- field = column_get(cls, fargs[0])
- table = get_model_for_field(cls, fargs[0])
+ field = getattr(cls, fargs[0])
+ table = cls
if len(fargs) > 1:
if field._type == 'many2one':
Target = pool.get(field.model_name)
m2o_search = [(fargs[1], domain[i][1], domain[i][2])]
- if ('active' in Target._fields
- or 'active' in Target._inherit_fields):
+ if 'active' in Target._fields:
m2o_search += [('active', 'in', (True, False))]
if hasattr(field, 'search'):
domain.extend([(fargs[0], 'in',
@@ -1411,10 +1279,7 @@ class ModelSQL(ModelStorage):
else:
Relation = Target
origin, target = field.field, 'id'
- if origin in Relation._fields:
- rev_field = Relation._fields[origin]
- else:
- rev_field = Relation._inherit_fields[origin][2]
+ rev_field = Relation._fields[origin]
if rev_field._type == 'reference':
sql_type = FIELDS[
cls.id._type].sql_type(cls.id)[0]
@@ -1452,10 +1317,7 @@ class ModelSQL(ModelStorage):
if Field.table_query():
table_query, table_args = Field.table_query()
table_query = '(' + table_query + ') AS '
- if field.field in Field._fields:
- rev_field = Field._fields[field.field]
- else:
- rev_field = Field._inherit_fields[field.field][2]
+ rev_field = Field._fields[field.field]
if rev_field._type == 'reference':
sql_type = FIELDS[cls.id._type].sql_type(cls.id)[0]
select = ('CAST(SPLIT_PART("%s", \',\', 2) AS %s)'
@@ -1546,11 +1408,7 @@ class ModelSQL(ModelStorage):
if Relation.table_query():
table_query, table_args = Relation.table_query()
table_query = '(' + table_query + ') AS '
- if field.origin in Relation._fields:
- origin_field = Relation._fields[field.origin]
- else:
- origin_field = \
- Relation._inherit_fields[field.origin][2]
+ origin_field = Relation._fields[field.origin]
if origin_field._type == 'reference':
sql_type = FIELDS[cls.id._type].sql_type(cls.id)[0]
select = ('CAST(SPLIT_PART("%s", \',\', 2) AS %s)'
@@ -1650,8 +1508,7 @@ class ModelSQL(ModelStorage):
if isinstance(domain[i][2], basestring):
Field = pool.get(field.model_name)
m2o_search = [('rec_name', domain[i][1], domain[i][2])]
- if ('active' in Field._fields
- or 'active' in Field._inherit_fields):
+ if 'active' in Field._fields:
m2o_search += [('active', 'in', (True, False))]
res_ids = map(int, Field.search(m2o_search, order=[]))
domain[i] = (domain[i][0], 'in', res_ids, table)
@@ -1722,10 +1579,10 @@ class ModelSQL(ModelStorage):
qu1, qu2 = [], []
for arg in domain:
- table = get_model_for_field(cls, arg[0])
- if table == cls and len(arg) > 3:
+ table = cls
+ if len(arg) > 3:
table = arg[3]
- column = column_get(table, arg[0])
+ column = getattr(table, arg[0])
if arg[1] in ('inselect', 'notinselect'):
clause = 'IN'
if arg[1] == 'notinselect':
@@ -1914,61 +1771,6 @@ class ModelSQL(ModelStorage):
tables.insert(0, table_join)
return order_by, tables, tables_args
- obj2 = None
- if obj._rec_name in obj._inherit_fields.keys():
- obj2 = pool.get(
- obj._inherit_fields[obj._rec_name][0])
- field_name = obj._rec_name
-
- if obj._order_name in obj._inherit_fields.keys():
- obj2 = pool.get(
- obj._inherit_fields[obj._order_name][0])
- field_name = obj._order_name
-
- if obj2 and field_name:
- table_name2 = obj2._table
- link_field2 = obj._inherits[obj2.__name__]
- order_by, tables, tables_args = \
- obj2._order_calc(field_name, otype)
-
- table_join = ('LEFT JOIN "' + table_name + '" AS '
- '"' + table_name + '.' + link_field + '" ON '
- '"%s.%s".id = "%s"."%s"'
- % (table_name, link_field, cls._table, link_field))
- for i in range(len(order_by)):
- if table_name in order_by[i]:
- order_by[i] = order_by[i].replace(table_name,
- table_name + '.' + link_field)
- for i in range(len(tables)):
- if table_name in tables[i]:
- args = tables_args.pop(tables[i], [])
- tables[i] = tables[i].replace(table_name,
- table_name + '.' + link_field)
- tables_args[tables[i]] = args
- if table_join not in tables:
- tables.insert(0, table_join)
- tables_args[table_join] = []
-
- table_join2 = ('LEFT JOIN "' + table_name2 + '" AS '
- '"' + table_name2 + '.' + link_field2 + '" ON '
- '"%s.%s".id = "%s.%s"."%s"'
- % (table_name2, link_field2, table_name, link_field,
- link_field2))
- for i in range(len(order_by)):
- if table_name2 in order_by[i]:
- order_by[i] = order_by[i].replace(table_name2,
- table_name2 + '.' + link_field2)
- for i in range(1, len(tables)):
- if table_name2 in tables[i]:
- args = tables_args.pop(tables[i], [])
- tables[i] = tables[i].replace(table_name2,
- table_name2 + '.' + link_field2)
- tables_args[tables[i]] = args
- if table_join2 not in tables:
- tables.insert(1, table_join2)
- tables_args[table_join2] = []
- return order_by, tables, tables_args
-
if (field_name in cls._fields
and getattr(cls._fields[field_name], 'translate', False)):
translation_table = ('ir_translation_%s_%s'
@@ -2049,18 +1851,6 @@ class ModelSQL(ModelStorage):
% (table_name, field_name, otype))
return order_by, tables, tables_args
- if field in cls._inherit_fields.keys():
- obj = pool.get(cls._inherit_fields[field][0])
- table_name = obj._table
- link_field = cls._inherits[obj.__name__]
- order_by, tables, tables_args = obj._order_calc(field, otype)
- table_join = ('LEFT JOIN "' + table_name + '" ON '
- '"%s".id = "%s"."%s"'
- % (table_name, cls._table, link_field))
- if table_join not in tables:
- tables.insert(0, table_join)
- return order_by, tables, tables_args
-
raise Exception('Error', 'Wrong field name (%s) for %s in order!' %
(field, cls.__name__))
diff --git a/trytond/model/modelstorage.py b/trytond/model/modelstorage.py
index 61beeaae6b..ca5cf87684 100644
--- a/trytond/model/modelstorage.py
+++ b/trytond/model/modelstorage.py
@@ -15,7 +15,7 @@ except ImportError:
import StringIO
from decimal import Decimal
-from itertools import islice, ifilter, ifilterfalse, chain, izip
+from itertools import islice, ifilter, chain, izip
from functools import reduce
from trytond.model import Model
@@ -304,10 +304,7 @@ class ModelStorage(Model):
field_defs[field_name]['relation'])
relation_field = field_defs[field_name]['relation_field']
if relation_field:
- if relation_field in Relation._fields:
- field = Relation._fields[relation_field]
- else:
- field = Relation._inherit_fields[relation_field][2]
+ field = Relation._fields[relation_field]
if field._type == 'reference':
value = str(new_record)
else:
@@ -368,8 +365,7 @@ class ModelStorage(Model):
records = cls.search(domain, offset=offset, limit=limit, order=order)
if not fields_names:
- fields_names = list(set(cls._fields.keys()
- + cls._inherit_fields.keys()))
+ fields_names = cls._fields.keys()
if 'id' not in fields_names:
fields_names.append('id')
return cls.read(map(int, records), fields_names)
@@ -380,10 +376,9 @@ class ModelStorage(Model):
domain = reduce_domain(domain)
# if the object has a field named 'active', filter out all inactive
# records unless they were explicitely asked for
- if not (('active' in cls._fields
- or 'active' in cls._inherit_fields.keys())
- and (active_test
- and Transaction().context.get('active_test', True))):
+ if not ('active' in cls._fields
+ and active_test
+ and Transaction().context.get('active_test', True)):
return domain
def process(domain):
@@ -417,8 +412,7 @@ class ModelStorage(Model):
It is used by the Function field rec_name.
'''
rec_name = self._rec_name
- if (rec_name not in self._fields
- and rec_name not in self._inherit_fields):
+ if rec_name not in self._fields:
rec_name = 'id'
return unicode(getattr(self, rec_name))
@@ -428,8 +422,7 @@ class ModelStorage(Model):
Return a list of arguments for search on rec_name.
'''
rec_name = cls._rec_name
- if (rec_name not in cls._fields
- and rec_name not in cls._inherit_fields):
+ if rec_name not in cls._fields:
return []
return [(rec_name,) + clause[1:]]
@@ -470,13 +463,7 @@ class ModelStorage(Model):
break
field_name = fields_tree[i]
eModel = pool.get(value.__name__)
- if field_name in eModel._fields:
- field = eModel._fields[field_name]
- elif field_name in eModel._inherit_fields:
- field = eModel._inherit_fields[field_name][2]
- else:
- raise Exception('Field %s not available on object "%s"'
- % (field_name, eModel.__name__))
+ field = eModel._fields[field_name]
if field.states and 'invisible' in field.states:
pyson_invisible = PYSONEncoder().encode(
field.states['invisible'])
@@ -833,13 +820,7 @@ class ModelStorage(Model):
Function that checks if there is no recursion in the tree
composed with parent as parent field name.
'''
- if parent in cls._fields:
- parent_type = cls._fields[parent]._type
- elif parent in cls._inherit_fields:
- parent_type = cls._inherit_fields[parent][2]._type
- else:
- raise Exception('Field %s not available on object "%s"'
- % (parent, cls.__name__))
+ parent_type = cls._fields[parent]._type
if parent_type not in ('many2one', 'many2many'):
raise Exception(
@@ -1161,8 +1142,7 @@ class ModelStorage(Model):
pool = Pool()
vals = {}
for field in defaults.keys():
- fld_def = (field in cls._fields) and cls._fields[field] \
- or cls._inherit_fields[field][2]
+ fld_def = cls._fields[field]
if fld_def._type in ('many2one', 'one2one'):
if isinstance(defaults[field], (list, tuple)):
vals[field] = defaults[field][0]
@@ -1223,13 +1203,10 @@ class ModelStorage(Model):
self._local_cache.counter = counter
# fetch the definition of the field
- if name in self._fields:
+ try:
field = self._fields[name]
- elif name in self._inherit_fields:
- field = self._inherit_fields[name][2]
- else:
- raise AttributeError("'%s' Model has no attribute '%s'"
- % (self.__name__, name))
+ except KeyError:
+ raise AttributeError('"%s" has no attribute "%s"' % (self, name))
try:
return self._local_cache[self.id][name]
@@ -1248,17 +1225,12 @@ class ModelStorage(Model):
if field.loading == 'eager':
FieldAccess = Pool().get('ir.model.field.access')
fread_accesses = {}
- for inherit_name in self._inherits:
- Inherit = Pool().get(inherit_name)
- fread_accesses.update(FieldAccess.check(inherit_name,
- Inherit._fields.keys(), 'read', access=True))
fread_accesses.update(FieldAccess.check(self.__name__,
self._fields.keys(), 'read', access=True))
to_remove = set(x for x, y in fread_accesses.iteritems()
if not y and x != name)
threshold = BROWSE_FIELD_TRESHOLD
- inherit_threshold = threshold - len(self._fields)
def not_cached(item):
fname, field = item
@@ -1274,17 +1246,6 @@ class ModelStorage(Model):
fname, field = item
return fname in self._fields
- if inherit_threshold > 0:
- ifields = ((fname, field)
- for fname, (_, _, field) in
- self._inherit_fields.iteritems())
- ifields = ifilterfalse(overrided,
- ifilter(to_load,
- ifilter(not_cached, ifields)))
- ifields = islice(ifields, 0, inherit_threshold)
- ffields.update(ifields)
- threshold -= inherit_threshold
-
ifields = ifilter(to_load,
ifilter(not_cached,
self._fields.iteritems()))
@@ -1294,11 +1255,7 @@ class ModelStorage(Model):
# add datetime_field
for field in ffields.values():
if hasattr(field, 'datetime_field') and field.datetime_field:
- if field.datetime_field in self._fields:
- datetime_field = self._fields[field.datetime_field]
- else:
- datetime_field = self._inherit_fields[
- field.datetime_field][2]
+ datetime_field = self._fields[field.datetime_field]
ffields[field.datetime_field] = datetime_field
def filter_(id_):
@@ -1393,10 +1350,7 @@ class ModelStorage(Model):
if not self._values:
return values
for fname, value in self._values.iteritems():
- if fname in self._fields:
- field = self._fields[fname]
- else:
- field = self._inherit_fields[fname][2]
+ field = self._fields[fname]
if field._type in ('many2one', 'one2one', 'reference'):
if value:
if value.id < 0 and field._type != 'reference':
@@ -1453,14 +1407,10 @@ class EvalEnvironment(dict):
def __getitem__(self, item):
if item.startswith('_parent_'):
field = item[8:]
- if field in self._model._fields:
- model_name = self._model._fields[field].model_name
- else:
- model_name = self._model._inherit_fields[field][2].model_name
+ model_name = self._model._fields[field].model_name
ParentModel = Pool().get(model_name)
return EvalEnvironment(getattr(self._record, field), ParentModel)
- if (item in self._model._fields
- or item in self._model._inherit_fields):
+ if item in self._model._fields:
value = getattr(self._record, item)
if isinstance(value, Model):
return value.id
diff --git a/trytond/model/modelview.py b/trytond/model/modelview.py
index 322eedf8b6..eba53c4488 100644
--- a/trytond/model/modelview.py
+++ b/trytond/model/modelview.py
@@ -327,24 +327,6 @@ class ModelView(Model):
if field_to_remove in field.depends:
fields_to_remove.append(name)
- # Find field inherited without read access
- for inherit_name in cls._inherits:
- Inherit = pool.get(inherit_name)
- fread_accesses = FieldAccess.check(Inherit.__name__,
- Inherit._fields.keys(), 'read', access=True)
- fields_to_remove += list(x for x, y in fread_accesses.iteritems()
- if not y and x not in cls._fields.keys())
-
- # Find relation field without read access
- for name, field in Inherit._fields.iteritems():
- if not check_relation(Inherit, field):
- fields_to_remove.append(name)
-
- for name, field in Inherit._fields.iteritems():
- for field_to_remove in fields_to_remove:
- if field_to_remove in field.depends:
- fields_to_remove.append(name)
-
# Remove field without read access
for field in fields_to_remove:
for element in tree.xpath(
@@ -372,26 +354,19 @@ class ModelView(Model):
if field_children:
fields_def.setdefault(field_children, {'name': field_children})
- model, field = None, None
if field_children in cls._fields:
- model = cls
field = cls._fields[field_children]
- elif field_children in cls._inherit_fields:
- model_name, model, field = cls._inherit_fields[field_children]
- if model and field and field.model_name == model.__name__:
fields_def.setdefault(field.field, {'name': field.field})
for field_name in fields_def.keys():
if field_name in cls._fields:
field = cls._fields[field_name]
- elif field_name in cls._inherit_fields:
- field = cls._inherit_fields[field_name][2]
else:
continue
for depend in field.depends:
fields_def.setdefault(depend, {'name': depend})
- if ('active' in cls._fields) or ('active' in cls._inherit_fields):
+ if 'active' in cls._fields:
fields_def.setdefault('active', {'name': 'active'})
arch = etree.tostring(tree, encoding='utf-8', pretty_print=False)
@@ -424,11 +399,7 @@ class ModelView(Model):
if element.get(attr):
fields_attrs.setdefault(element.get(attr), {})
try:
- if element.get(attr) in cls._fields:
- field = cls._fields[element.get(attr)]
- else:
- field = cls._inherit_fields[element.get(
- attr)][2]
+ field = cls._fields[element.get(attr)]
if hasattr(field, 'model_name'):
relation = field.model_name
else:
diff --git a/trytond/res/ir.xml b/trytond/res/ir.xml
index a071020197..dd99cc253a 100644
--- a/trytond/res/ir.xml
+++ b/trytond/res/ir.xml
@@ -459,6 +459,59 @@ this repository contains the full copyright notices and license terms. -->
[('groups', '=', None)]
+
+
+
+
+
+
+ [('groups', 'in', [g.id for g in user.groups])]
+
+
+
+ [('groups', '=', None)]
+
+
+
+
+
+
+
+
+ [('groups', 'in', [g.id for g in user.groups])]
+
+
+
+ [('groups', '=', None)]
+
+
+
+
+
+
+
+
+ [('groups', 'in', [g.id for g in user.groups])]
+
+
+
+ [('groups', '=', None)]
+
+
+
+
+
+
+
+
+ [('groups', 'in', [g.id for g in user.groups])]
+
+
+
+ [('groups', '=', None)]
+
+
+
diff --git a/trytond/test/__init__.py b/trytond/test/__init__.py
index 6528488867..8d200096c8 100644
--- a/trytond/test/__init__.py
+++ b/trytond/test/__init__.py
@@ -90,11 +90,6 @@ def register():
DictRequired,
Singleton,
URLObject,
- ModelInherits,
- ModelInheritsSubModel,
- ModelInheritsSubSubModel,
- ModelInheritsSubSubSubModel,
- ModelInheritsOverriddenFieldModel,
ModelSQLRequiredField,
MPTT,
ImportDataBoolean,
diff --git a/trytond/test/model.py b/trytond/test/model.py
index ff5a006cad..607f6ca9fb 100644
--- a/trytond/test/model.py
+++ b/trytond/test/model.py
@@ -3,9 +3,7 @@
from trytond.model import ModelSingleton, ModelSQL, fields
__all__ = [
- 'Singleton', 'URLObject', 'ModelInherits', 'ModelInheritsSubModel',
- 'ModelInheritsSubSubModel', 'ModelInheritsSubSubSubModel',
- 'ModelInheritsOverriddenFieldModel', 'ModelSQLRequiredField'
+ 'Singleton', 'URLObject', 'ModelSQLRequiredField',
]
@@ -25,53 +23,6 @@ class URLObject(ModelSQL):
name = fields.Char('Name')
-class ModelInherits(ModelSQL):
- 'Model Inherits'
- __name__ = 'test.model_inherits'
-
- name = fields.Char('Name')
-
-
-class ModelInheritsSubModel(ModelSQL):
- 'Model Inherits Sub-Model'
- __name__ = 'test.submodel'
- _inherits = {'test.model_inherits': 'parent_model'}
-
- subfield = fields.Char('SubField')
- parent_model = fields.Many2One('test.model_inherits', 'Parent model',
- required=True)
-
-
-class ModelInheritsSubSubModel(ModelSQL):
- 'Model Inherits Sub-Sub-Model'
- __name__ = 'test.subsubmodel'
- _inherits = {'test.submodel': 'parent_model'}
-
- subsubfield = fields.Char('SubField')
- parent_model = fields.Many2One('test.submodel', 'Parent model',
- required=True)
-
-
-class ModelInheritsSubSubSubModel(ModelSQL):
- 'Model Inherits Sub-Sub-Sub-Model'
- __name__ = 'test.subsubsubmodel'
- _inherits = {'test.subsubmodel': 'parent_model'}
-
- subsubsubfield = fields.Char('SubField')
- parent_model = fields.Many2One('test.subsubmodel', 'Parent model',
- required=True)
-
-
-class ModelInheritsOverriddenFieldModel(ModelSQL):
- 'Model Inherits Overridden Field Model'
- __name__ = 'test.overriddeninheritedfieldmodel'
- _inherits = {'test.subsubmodel': 'parent_model'}
-
- subfield = fields.Integer('Overridden field')
- parent_model = fields.Many2One('test.subsubmodel', 'Parent model',
- required=True)
-
-
class ModelSQLRequiredField(ModelSQL):
'model with a required field'
__name__ = 'test.modelsql'
diff --git a/trytond/tests/test_model_inherits.py b/trytond/tests/test_model_inherits.py
deleted file mode 100644
index 1f7282c3f8..0000000000
--- a/trytond/tests/test_model_inherits.py
+++ /dev/null
@@ -1,139 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: utf-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.
-import unittest
-from trytond.tests.test_tryton import POOL, DB_NAME, USER, CONTEXT, \
- install_module
-from trytond.transaction import Transaction
-
-
-class ModelInheritsTestCase(unittest.TestCase):
- '''
- Test ModelInheritSearch
- '''
-
- def setUp(self):
- install_module('test')
- self.parent = POOL.get('test.model_inherits')
- self.sub = POOL.get('test.submodel')
- self.subsub = POOL.get('test.subsubmodel')
- self.subsubsub = POOL.get('test.subsubsubmodel')
- self.overridden = POOL.get('test.overriddeninheritedfieldmodel')
-
- def create_data(self):
- parent_id, = self.parent.create([{'name': 'parent'}])
- sub_id, = self.sub.create([{
- 'name': 'sub',
- 'subfield': 'level1',
- }])
- subsub_id, = self.subsub.create([{
- 'name': 'subsub',
- 'subfield': 'level2',
- 'subsubfield': 'ssfcontent',
- }])
- subsubsub_id, = self.subsubsub.create([{
- 'name': 'subsubsub',
- 'subfield': 'level3',
- 'subsubfield': 'ssfcontent2',
- 'subsubsubfield': 'sssfcontent',
- }])
- overridden_id, = self.overridden.create([{
- 'name': 'overridden',
- 'subfield': 3,
- }])
- return (parent_id, sub_id, subsub_id, subsubsub_id, overridden_id)
-
- def test0010selfsearch(self):
- '''
- Test searching on own field
- '''
- with Transaction().start(DB_NAME, USER,
- context=CONTEXT) as transaction:
-
- (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \
- self.create_data()
-
- ids = self.subsubsub.search([
- ('subsubsubfield', '=', 'sssfcontent'),
- ])
- self.assertEqual(ids, [subsubsub_id])
-
- transaction.cursor.rollback()
-
- def test0020parentsearch(self):
- '''
- Test searching on parent field
- '''
- with Transaction().start(DB_NAME, USER,
- context=CONTEXT) as transaction:
-
- (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \
- self.create_data()
-
- ids = self.subsubsub.search([('subsubfield', '=', 'ssfcontent2')])
- self.assertEqual(ids, [subsubsub_id])
-
- ids = self.subsubsub.search([('subsubfield', '=', 'ssfcontent')])
- self.assertEqual(ids, [])
-
- transaction.cursor.rollback()
-
- def test0030granparentsearch(self):
- '''
- Test searching on granparent field
- '''
- with Transaction().start(DB_NAME, USER,
- context=CONTEXT) as transaction:
-
- (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \
- self.create_data()
-
- ids = self.subsubsub.search([('subfield', '=', 'level3')])
- self.assertEqual(ids, [subsubsub_id])
-
- ids = self.subsubsub.search([('subfield', '=', 'level1')])
- self.assertEqual(ids, [])
-
- transaction.cursor.rollback()
-
- def test0040greatgranparentsearch(self):
- '''
- Test searching on greatgranparent field
- '''
- with Transaction().start(DB_NAME, USER,
- context=CONTEXT) as transaction:
-
- (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \
- self.create_data()
-
- ids = self.subsubsub.search([('name', '=', 'subsubsub')])
- self.assertEqual(ids, [subsubsub_id])
-
- ids = self.subsubsub.search([('name', '=', 'parent')])
- self.assertEqual(ids, [])
-
- transaction.cursor.rollback()
-
- def test0050overriddenfieldsearch(self):
- '''
- Test searching on greatgranparent field
- '''
- with Transaction().start(DB_NAME, USER,
- context=CONTEXT) as transaction:
-
- (_parent_id, _sub_id, _subsub_id, subsubsub_id, overridden_id) = \
- self.create_data()
-
- ids = self.overridden.search([('subfield', '=', 3)])
- self.assertEqual(ids, [overridden_id])
-
- transaction.cursor.rollback()
-
-
-def suite():
- return unittest.TestLoader().loadTestsFromTestCase(ModelInheritsTestCase)
-
-if __name__ == '__main__':
- suite = suite()
- unittest.TextTestRunner(verbosity=2).run(suite)
diff --git a/trytond/tests/test_tryton.py b/trytond/tests/test_tryton.py
index e01eb72fd0..71bf65b921 100644
--- a/trytond/tests/test_tryton.py
+++ b/trytond/tests/test_tryton.py
@@ -255,8 +255,6 @@ def all_suite():
suite_.addTests(test_mixins.suite())
import trytond.tests.test_wizard as test_wizard
suite_.addTests(test_wizard.suite())
- import trytond.tests.test_model_inherits as test_inherits
- suite_.addTests(test_inherits.suite())
import trytond.tests.test_modelsql as test_modelsql
suite_.addTests(test_modelsql.suite())
import trytond.tests.test_cache as test_cache