diff options
Diffstat (limited to 'odoo')
| -rw-r--r-- | odoo/addons/base/i18n/base.pot | 2 | ||||
| -rw-r--r-- | odoo/addons/base/ir/ir_model.py | 11 | ||||
| -rw-r--r-- | odoo/addons/base/ir/ir_qweb/qweb.py | 2 | ||||
| -rw-r--r-- | odoo/addons/base/res/res_users.py | 2 | ||||
| -rw-r--r-- | odoo/addons/base/tests/test_qweb.py | 10 | ||||
| -rw-r--r-- | odoo/models.py | 12 | ||||
| -rw-r--r-- | odoo/modules/registry.py | 35 |
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. |
