summaryrefslogtreecommitdiff
path: root/odoo
diff options
context:
space:
mode:
Diffstat (limited to 'odoo')
-rw-r--r--odoo/addons/base/i18n/base.pot2
-rw-r--r--odoo/addons/base/ir/ir_model.py11
-rw-r--r--odoo/addons/base/ir/ir_qweb/qweb.py2
-rw-r--r--odoo/addons/base/res/res_users.py2
-rw-r--r--odoo/addons/base/tests/test_qweb.py10
-rw-r--r--odoo/models.py12
-rw-r--r--odoo/modules/registry.py35
7 files changed, 48 insertions, 26 deletions
diff --git a/odoo/addons/base/i18n/base.pot b/odoo/addons/base/i18n/base.pot
index 6fa284e7b7f..7394362b3e6 100644
--- a/odoo/addons/base/i18n/base.pot
+++ b/odoo/addons/base/i18n/base.pot
@@ -8826,7 +8826,7 @@ msgstr ""
#. module: base
#: code:addons/base/res/res_users.py:316
#, python-format
-msgid "Invalid group by"
+msgid "Invalid 'group by' parameter"
msgstr ""
#. module: base
diff --git a/odoo/addons/base/ir/ir_model.py b/odoo/addons/base/ir/ir_model.py
index a1652323180..5d3260e58f2 100644
--- a/odoo/addons/base/ir/ir_model.py
+++ b/odoo/addons/base/ir/ir_model.py
@@ -414,6 +414,7 @@ class IrModelFields(models.Model):
any(field.state != 'manual' for field in self):
raise UserError(_("This column contains module data and cannot be removed!"))
+ model_names = self.mapped('model')
self._drop_column()
res = super(IrModelFields, self).unlink()
@@ -423,6 +424,8 @@ class IrModelFields(models.Model):
self._cr.commit()
api.Environment.reset()
registry = Registry.new(self._cr.dbname)
+ models = registry.descendants(model_names, '_inherits')
+ registry.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
registry.signal_registry_change()
return res
@@ -455,8 +458,9 @@ class IrModelFields(models.Model):
if vals['model'] in self.pool:
# setup models; this re-initializes model in registry
self.pool.setup_models(self._cr, partial=(not self.pool.ready))
- # update database schema
- self.pool.init_models(self._cr, [vals['model']], dict(self._context, update_custom_fields=True))
+ # update database schema of model and its descendant models
+ models = self.pool.descendants([vals['model']], '_inherits')
+ self.pool.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
self.pool.signal_registry_change()
return res
@@ -538,7 +542,8 @@ class IrModelFields(models.Model):
if patched_models:
# update the database schema of the models to patch
- self.pool.init_models(self._cr, patched_models, dict(self._context, update_custom_fields=True))
+ models = self.pool.descendants(patched_models, '_inherits')
+ self.pool.init_models(self._cr, models, dict(self._context, update_custom_fields=True))
if column_rename or patched_models:
self.pool.signal_registry_change()
diff --git a/odoo/addons/base/ir/ir_qweb/qweb.py b/odoo/addons/base/ir/ir_qweb/qweb.py
index ad0aaaa5f88..a50f478779f 100644
--- a/odoo/addons/base/ir/ir_qweb/qweb.py
+++ b/odoo/addons/base/ir/ir_qweb/qweb.py
@@ -246,7 +246,7 @@ class QWeb(object):
"""
body = []
self.compile(template, options)(self, body.append, values or {})
- return u''.join(body)
+ return u''.join(body).encode('utf8')
def compile(self, template, options):
""" Compile the given template into a rendering function::
diff --git a/odoo/addons/base/res/res_users.py b/odoo/addons/base/res/res_users.py
index aa269952e0b..2b5cff01818 100644
--- a/odoo/addons/base/res/res_users.py
+++ b/odoo/addons/base/res/res_users.py
@@ -313,7 +313,7 @@ class Users(models.Model):
if self._uid != SUPERUSER_ID:
groupby_fields = set([groupby] if isinstance(groupby, basestring) else groupby)
if groupby_fields.intersection(USER_PRIVATE_FIELDS):
- raise AccessError(_('Invalid group by'))
+ raise AccessError(_("Invalid 'group by' parameter"))
return super(Users, self).read_group(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
@api.model
diff --git a/odoo/addons/base/tests/test_qweb.py b/odoo/addons/base/tests/test_qweb.py
index 949fc72ad3e..0210b03df05 100644
--- a/odoo/addons/base/tests/test_qweb.py
+++ b/odoo/addons/base/tests/test_qweb.py
@@ -25,7 +25,7 @@ class TestQWebTField(TransactionCase):
field = etree.Element('span', {'t-field': u'company.name'})
company = self.env['res.company'].create({'name': "My Test Company"})
- result = self.engine.render(field, {'company': company}).encode('utf-8')
+ result = self.engine.render(field, {'company': company})
self.assertEqual(
result,
'<span data-oe-model="res.company" data-oe-id="%d" '
@@ -41,7 +41,7 @@ class TestQWebTField(TransactionCase):
s = u"Testing «ταБЬℓσ»: 1<2 & 4+1>3, now 20% off!"
company = self.env['res.company'].create({'name': s})
- result = self.engine.render(field, {'company': company}).encode('utf-8')
+ result = self.engine.render(field, {'company': company})
self.assertEqual(
result,
'<span data-oe-model="res.company" data-oe-id="%d" '
@@ -56,13 +56,13 @@ class TestQWebTField(TransactionCase):
field = etree.Element('td', {'t-field': u'company.name'})
with self.assertRaisesRegexp(QWebException, r'^RTE widgets do not work correctly'):
- self.engine.render(field, {'company': None}).encode('utf-8')
+ self.engine.render(field, {'company': None})
def test_reject_t_tag(self):
field = etree.Element('t', {'t-field': u'company.name'})
with self.assertRaisesRegexp(QWebException, r'^t-field can not be used on a t element'):
- self.engine.render(field, {'company': None}).encode('utf-8')
+ self.engine.render(field, {'company': None})
from copy import deepcopy
@@ -128,7 +128,7 @@ class TestQWeb(TransactionCase):
result = doc.find('result[@id="{}"]'.format(template)).text
self.assertEqual(
- qweb.render(template, values=params, load=loader).strip().encode('utf-8'),
+ qweb.render(template, values=params, load=loader).strip(),
(result or u'').strip().encode('utf-8'),
template
)
diff --git a/odoo/models.py b/odoo/models.py
index 9c081ff53d0..a912af902c4 100644
--- a/odoo/models.py
+++ b/odoo/models.py
@@ -377,6 +377,7 @@ class BaseModel(object):
cr.execute(query, vals)
self.invalidate_cache()
+
@api.model
def _add_field(self, name, field):
""" Add the given ``field`` under the given ``name`` in the class """
@@ -536,6 +537,7 @@ class BaseModel(object):
'_register': False,
'_original_module': cls._module,
'_inherit_children': OrderedSet(), # names of children models
+ '_inherits_children': set(), # names of children models
'_fields': {}, # populated in _setup_base()
})
check_parent = cls._build_model_check_parent
@@ -633,7 +635,11 @@ class BaseModel(object):
cls._sequence = cls._sequence or (cls._table + '_id_seq')
cls._constraints = cls._constraints.values()
- # recompute attributes of children models
+ # update _inherits_children of parent models
+ for parent_name in cls._inherits:
+ pool[parent_name]._inherits_children.add(cls._name)
+
+ # recompute attributes of _inherit_children models
for child_name in cls._inherit_children:
child_class = pool[child_name]
child_class._build_model_attributes(pool)
@@ -1933,7 +1939,7 @@ class BaseModel(object):
"""
result = self._read_group_raw(domain, fields, groupby, offset=offset, limit=limit, orderby=orderby, lazy=lazy)
- groupby = [groupby] if isinstance(groupby, basestring) else groupby
+ groupby = [groupby] if isinstance(groupby, basestring) else list(OrderedSet(groupby))
dt = [
f for f in groupby
if self._fields[f.split(':')[0]].type in ('date', 'datetime')
@@ -1957,7 +1963,7 @@ class BaseModel(object):
query = self._where_calc(domain)
fields = fields or [f.name for f in self._fields.itervalues() if f.store]
- groupby = [groupby] if isinstance(groupby, basestring) else groupby
+ groupby = [groupby] if isinstance(groupby, basestring) else list(OrderedSet(groupby))
groupby_list = groupby[:1] if lazy else groupby
annotated_groupbys = [self._read_group_process_groupby(gb, query) for gb in groupby_list]
groupby_fields = [g['field'] for g in annotated_groupbys]
diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py
index aba103ffcfd..8de7172ae89 100644
--- a/odoo/modules/registry.py
+++ b/odoo/modules/registry.py
@@ -4,16 +4,17 @@
""" Models registries.
"""
-from collections import Mapping, defaultdict
+from collections import Mapping, defaultdict, deque
from contextlib import closing
+from operator import attrgetter
import logging
import os
import threading
import odoo
from .. import SUPERUSER_ID
-from odoo.tools import assertion_report, lazy_classproperty, config, \
- lazy_property, topological_sort, OrderedSet
+from odoo.tools import (assertion_report, lazy_classproperty, config,
+ lazy_property, topological_sort, OrderedSet)
from odoo.tools.lru import LRU
_logger = logging.getLogger(__name__)
@@ -222,6 +223,22 @@ class Registry(Mapping):
env[model_name]._parent_store_compute()
self._init = False
+ def descendants(self, model_names, *kinds):
+ """ Return the models corresponding to ``model_names`` and all those
+ that inherit/inherits from them.
+ """
+ assert all(kind in ('_inherit', '_inherits') for kind in kinds)
+ funcs = [attrgetter(kind + '_children') for kind in kinds]
+
+ models = OrderedSet()
+ queue = deque(model_names)
+ while queue:
+ model = self[queue.popleft()]
+ models.add(model)
+ for func in funcs:
+ queue.extend(func(model))
+ return models
+
def load(self, cr, module):
""" Load a given module in the registry, and return the names of the
modified models.
@@ -234,23 +251,17 @@ class Registry(Mapping):
"""
from .. import models
- loaded_models = OrderedSet()
- def mark_loaded(model):
- # recursively mark model and its children
- loaded_models.add(model._name)
- for child_name in model._inherit_children:
- mark_loaded(self[child_name])
-
lazy_property.reset_all(self)
# Instantiate registered classes (via the MetaModel automatic discovery
# or via explicit constructor call), and add them to the pool.
+ model_names = []
for cls in models.MetaModel.module_to_models.get(module.name, []):
# models register themselves in self.models
model = cls._build_model(self, cr)
- mark_loaded(model)
+ model_names.append(model._name)
- return list(loaded_models)
+ return self.descendants(model_names, '_inherit')
def setup_models(self, cr, partial=False):
""" Complete the setup of models.